]> git.proxmox.com Git - mirror_edk2.git/blob - ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/FileBuffer.c
ShellPkg/UefiShellDebug1CommandsLib: Remove unnecessary EFIAPI
[mirror_edk2.git] / ShellPkg / Library / UefiShellDebug1CommandsLib / Edit / FileBuffer.c
1 /** @file
2 Implements filebuffer interface functions.
3
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
9
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.
12
13 **/
14
15 #include "TextEditor.h"
16 #include <Guid/FileSystemInfo.h>
17 #include <Library/FileHandleLib.h>
18
19 EFI_EDITOR_FILE_BUFFER FileBuffer;
20 EFI_EDITOR_FILE_BUFFER FileBufferBackupVar;
21
22 //
23 // for basic initialization of FileBuffer
24 //
25 EFI_EDITOR_FILE_BUFFER FileBufferConst = {
26 NULL,
27 FileTypeUnicode,
28 NULL,
29 NULL,
30 0,
31 {
32 0,
33 0
34 },
35 {
36 0,
37 0
38 },
39 {
40 0,
41 0
42 },
43 {
44 0,
45 0
46 },
47 FALSE,
48 TRUE,
49 FALSE,
50 NULL
51 };
52
53 //
54 // the whole edit area needs to be refreshed
55 //
56 BOOLEAN FileBufferNeedRefresh;
57
58 //
59 // only the current line in edit area needs to be refresh
60 //
61 BOOLEAN FileBufferOnlyLineNeedRefresh;
62
63 BOOLEAN FileBufferMouseNeedRefresh;
64
65 extern BOOLEAN EditorMouseAction;
66
67 /**
68 Initialization function for FileBuffer.
69
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.
73 **/
74 EFI_STATUS
75 FileBufferInit (
76 VOID
77 )
78 {
79 //
80 // basically initialize the FileBuffer
81 //
82 CopyMem (&FileBuffer , &FileBufferConst, sizeof (EFI_EDITOR_FILE_BUFFER));
83 CopyMem (&FileBufferBackupVar, &FileBufferConst, sizeof (EFI_EDITOR_FILE_BUFFER));
84
85 //
86 // set default FileName
87 //
88 FileBuffer.FileName = EditGetDefaultFileName (L"txt");
89 if (FileBuffer.FileName == NULL) {
90 return EFI_LOAD_ERROR;
91 }
92
93 FileBuffer.ListHead = AllocateZeroPool (sizeof (LIST_ENTRY));
94 if (FileBuffer.ListHead == NULL) {
95 return EFI_OUT_OF_RESOURCES;
96 }
97
98 InitializeListHead (FileBuffer.ListHead);
99
100 FileBuffer.DisplayPosition.Row = 2;
101 FileBuffer.DisplayPosition.Column = 1;
102 FileBuffer.LowVisibleRange.Row = 2;
103 FileBuffer.LowVisibleRange.Column = 1;
104
105 FileBufferNeedRefresh = FALSE;
106 FileBufferMouseNeedRefresh = FALSE;
107 FileBufferOnlyLineNeedRefresh = FALSE;
108
109 return EFI_SUCCESS;
110 }
111
112 /**
113 Backup function for FileBuffer. Only backup the following items:
114 Mouse/Cursor position
115 File Name, Type, ReadOnly, Modified
116 Insert Mode
117
118 This is for making the file buffer refresh as few as possible.
119
120 @retval EFI_SUCCESS The backup operation was successful.
121 **/
122 EFI_STATUS
123 FileBufferBackup (
124 VOID
125 )
126 {
127 FileBufferBackupVar.MousePosition = FileBuffer.MousePosition;
128
129 SHELL_FREE_NON_NULL (FileBufferBackupVar.FileName);
130 FileBufferBackupVar.FileName = NULL;
131 FileBufferBackupVar.FileName = StrnCatGrow (&FileBufferBackupVar.FileName, NULL, FileBuffer.FileName, 0);
132
133 FileBufferBackupVar.ModeInsert = FileBuffer.ModeInsert;
134 FileBufferBackupVar.FileType = FileBuffer.FileType;
135
136 FileBufferBackupVar.FilePosition = FileBuffer.FilePosition;
137 FileBufferBackupVar.LowVisibleRange = FileBuffer.LowVisibleRange;
138
139 FileBufferBackupVar.FileModified = FileBuffer.FileModified;
140 FileBufferBackupVar.ReadOnly = FileBuffer.ReadOnly;
141
142 return EFI_SUCCESS;
143 }
144
145 /**
146 Advance to the next Count lines
147
148 @param[in] Count The line number to advance by.
149 @param[in] CurrentLine The pointer to the current line structure.
150 @param[in] LineList The pointer to the linked list of lines.
151
152 @retval NULL There was an error.
153 @return The line structure after the advance.
154 **/
155 EFI_EDITOR_LINE *
156 InternalEditorMiscLineAdvance (
157 IN CONST UINTN Count,
158 IN CONST EFI_EDITOR_LINE *CurrentLine,
159 IN CONST LIST_ENTRY *LineList
160 )
161
162 {
163 UINTN Index;
164 CONST EFI_EDITOR_LINE *Line;
165
166 if (CurrentLine == NULL || LineList == NULL) {
167 return NULL;
168 }
169
170 for (Line = CurrentLine, Index = 0; Index < Count; Index++) {
171 //
172 // if already last line
173 //
174 if (Line->Link.ForwardLink == LineList) {
175 return NULL;
176 }
177
178 Line = CR (Line->Link.ForwardLink, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE);
179 }
180
181 return ((EFI_EDITOR_LINE *)Line);
182 }
183
184 /**
185 Retreat to the previous Count lines.
186
187 @param[in] Count The line number to retreat by.
188 @param[in] CurrentLine The pointer to the current line structure.
189 @param[in] LineList The pointer to the linked list of lines.
190
191 @retval NULL There was an error.
192 @return The line structure after the retreat.
193 **/
194 EFI_EDITOR_LINE *
195 InternalEditorMiscLineRetreat (
196 IN CONST UINTN Count,
197 IN CONST EFI_EDITOR_LINE *CurrentLine,
198 IN CONST LIST_ENTRY *LineList
199 )
200
201 {
202 UINTN Index;
203 CONST EFI_EDITOR_LINE *Line;
204
205 if (CurrentLine == NULL || LineList == NULL) {
206 return NULL;
207 }
208
209 for (Line = CurrentLine, Index = 0; Index < Count; Index++) {
210 //
211 // already the first line
212 //
213 if (Line->Link.BackLink == LineList) {
214 return NULL;
215 }
216
217 Line = CR (Line->Link.BackLink, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE);
218 }
219
220 return ((EFI_EDITOR_LINE *)Line);
221 }
222
223 /**
224 Advance/Retreat lines
225
226 @param[in] Count line number to advance/retreat
227 >0 : advance
228 <0 : retreat
229
230 @retval NULL An error occured.
231 @return The line after advance/retreat.
232 **/
233 EFI_EDITOR_LINE *
234 MoveLine (
235 IN CONST INTN Count
236 )
237 {
238 EFI_EDITOR_LINE *Line;
239 UINTN AbsCount;
240
241 //
242 // if < 0, then retreat
243 // if > 0, the advance
244 //
245 if (Count <= 0) {
246 AbsCount = (UINTN)ABS(Count);
247 Line = InternalEditorMiscLineRetreat (AbsCount,MainEditor.FileBuffer->CurrentLine,MainEditor.FileBuffer->ListHead);
248 } else {
249 Line = InternalEditorMiscLineAdvance ((UINTN)Count,MainEditor.FileBuffer->CurrentLine,MainEditor.FileBuffer->ListHead);
250 }
251
252 return Line;
253 }
254
255 /**
256 Function to update the 'screen' to display the mouse position.
257
258 @retval EFI_SUCCESS The backup operation was successful.
259 **/
260 EFI_STATUS
261 FileBufferRestoreMousePosition (
262 VOID
263 )
264 {
265 EFI_EDITOR_COLOR_UNION Orig;
266 EFI_EDITOR_COLOR_UNION New;
267 UINTN FRow;
268 UINTN FColumn;
269 BOOLEAN HasCharacter;
270 EFI_EDITOR_LINE *CurrentLine;
271 EFI_EDITOR_LINE *Line;
272 CHAR16 Value;
273
274 //
275 // variable initialization
276 //
277 Line = NULL;
278
279 if (MainEditor.MouseSupported) {
280
281 if (FileBufferMouseNeedRefresh) {
282
283 FileBufferMouseNeedRefresh = FALSE;
284
285 //
286 // if mouse position not moved and only mouse action
287 // so do not need to refresh mouse position
288 //
289 if ((FileBuffer.MousePosition.Row == FileBufferBackupVar.MousePosition.Row &&
290 FileBuffer.MousePosition.Column == FileBufferBackupVar.MousePosition.Column)
291 && EditorMouseAction) {
292 return EFI_SUCCESS;
293 }
294 //
295 // backup the old screen attributes
296 //
297 Orig = MainEditor.ColorAttributes;
298 New.Data = 0;
299 New.Colors.Foreground = Orig.Colors.Background & 0xF;
300 New.Colors.Background = Orig.Colors.Foreground & 0x7;
301
302 //
303 // clear the old mouse position
304 //
305 FRow = FileBuffer.LowVisibleRange.Row + FileBufferBackupVar.MousePosition.Row - 2;
306
307 FColumn = FileBuffer.LowVisibleRange.Column + FileBufferBackupVar.MousePosition.Column - 1;
308
309 HasCharacter = TRUE;
310 if (FRow > FileBuffer.NumLines) {
311 HasCharacter = FALSE;
312 } else {
313 CurrentLine = FileBuffer.CurrentLine;
314 Line = MoveLine (FRow - FileBuffer.FilePosition.Row);
315
316 if (Line == NULL || FColumn > Line->Size) {
317 HasCharacter = FALSE;
318 }
319
320 FileBuffer.CurrentLine = CurrentLine;
321 }
322
323 ShellPrintEx (
324 (INT32)FileBufferBackupVar.MousePosition.Column - 1,
325 (INT32)FileBufferBackupVar.MousePosition.Row - 1,
326 L" "
327 );
328
329 if (HasCharacter) {
330 Value = (Line->Buffer[FColumn - 1]);
331 ShellPrintEx (
332 (INT32)FileBufferBackupVar.MousePosition.Column - 1,
333 (INT32)FileBufferBackupVar.MousePosition.Row - 1,
334 L"%c",
335 Value
336 );
337 }
338 //
339 // set the new mouse position
340 //
341 gST->ConOut->SetAttribute (gST->ConOut, New.Data & 0x7F);
342
343 //
344 // clear the old mouse position
345 //
346 FRow = FileBuffer.LowVisibleRange.Row + FileBuffer.MousePosition.Row - 2;
347 FColumn = FileBuffer.LowVisibleRange.Column + FileBuffer.MousePosition.Column - 1;
348
349 HasCharacter = TRUE;
350 if (FRow > FileBuffer.NumLines) {
351 HasCharacter = FALSE;
352 } else {
353 CurrentLine = FileBuffer.CurrentLine;
354 Line = MoveLine (FRow - FileBuffer.FilePosition.Row);
355
356 if (Line == NULL || FColumn > Line->Size) {
357 HasCharacter = FALSE;
358 }
359
360 FileBuffer.CurrentLine = CurrentLine;
361 }
362
363 ShellPrintEx (
364 (INT32)FileBuffer.MousePosition.Column - 1,
365 (INT32)FileBuffer.MousePosition.Row - 1,
366 L" "
367 );
368
369 if (HasCharacter) {
370 Value = Line->Buffer[FColumn - 1];
371 ShellPrintEx (
372 (INT32)FileBuffer.MousePosition.Column - 1,
373 (INT32)FileBuffer.MousePosition.Row - 1,
374 L"%c",
375 Value
376 );
377 }
378 //
379 // end of HasCharacter
380 //
381 gST->ConOut->SetAttribute (gST->ConOut, Orig.Data);
382 }
383 //
384 // end of MouseNeedRefresh
385 //
386 }
387 //
388 // end of MouseSupported
389 //
390 return EFI_SUCCESS;
391 }
392
393 /**
394 Free all the lines in FileBuffer
395 Fields affected:
396 Lines
397 CurrentLine
398 NumLines
399 ListHead
400
401 @retval EFI_SUCCESS The operation was successful.
402 **/
403 EFI_STATUS
404 FileBufferFreeLines (
405 VOID
406 )
407 {
408 LIST_ENTRY *Link;
409 EFI_EDITOR_LINE *Line;
410
411 //
412 // free all the lines
413 //
414 if (FileBuffer.Lines != NULL) {
415
416 Line = FileBuffer.Lines;
417 Link = &(Line->Link);
418 do {
419 Line = CR (Link, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE);
420 Link = Link->ForwardLink;
421
422 //
423 // free line's buffer and line itself
424 //
425 LineFree (Line);
426 } while (Link != FileBuffer.ListHead);
427 }
428 //
429 // clean the line list related structure
430 //
431 FileBuffer.Lines = NULL;
432 FileBuffer.CurrentLine = NULL;
433 FileBuffer.NumLines = 0;
434
435 FileBuffer.ListHead->ForwardLink = FileBuffer.ListHead;
436 FileBuffer.ListHead->BackLink = FileBuffer.ListHead;
437
438 return EFI_SUCCESS;
439 }
440
441 /**
442 Cleanup function for FileBuffer.
443
444 @retval EFI_SUCCESS The cleanup was successful.
445 **/
446 EFI_STATUS
447 FileBufferCleanup (
448 VOID
449 )
450 {
451 EFI_STATUS Status;
452
453 SHELL_FREE_NON_NULL (FileBuffer.FileName);
454
455 //
456 // free all the lines
457 //
458 Status = FileBufferFreeLines ();
459
460 SHELL_FREE_NON_NULL (FileBuffer.ListHead);
461 FileBuffer.ListHead = NULL;
462
463 SHELL_FREE_NON_NULL (FileBufferBackupVar.FileName);
464 return Status;
465
466 }
467
468 /**
469 Print a line specified by Line on a row specified by Row of the screen.
470
471 @param[in] Line The line to print.
472 @param[in] Row The row on the screen to print onto (begin from 1).
473
474 @retval EFI_SUCCESS The printing was successful.
475 **/
476 EFI_STATUS
477 FileBufferPrintLine (
478 IN CONST EFI_EDITOR_LINE *Line,
479 IN CONST UINTN Row
480 )
481 {
482
483 CHAR16 *Buffer;
484 UINTN Limit;
485 CHAR16 *PrintLine;
486 CHAR16 *PrintLine2;
487 UINTN BufLen;
488
489 //
490 // print start from correct character
491 //
492 Buffer = Line->Buffer + FileBuffer.LowVisibleRange.Column - 1;
493
494 Limit = Line->Size - FileBuffer.LowVisibleRange.Column + 1;
495 if (Limit > Line->Size) {
496 Limit = 0;
497 }
498
499 BufLen = (MainEditor.ScreenSize.Column + 1) * sizeof (CHAR16);
500 PrintLine = AllocatePool (BufLen);
501 if (PrintLine != NULL) {
502 StrnCpyS (PrintLine, BufLen/sizeof(CHAR16), Buffer, MIN(Limit, MainEditor.ScreenSize.Column));
503 for (; Limit < MainEditor.ScreenSize.Column; Limit++) {
504 PrintLine[Limit] = L' ';
505 }
506
507 PrintLine[MainEditor.ScreenSize.Column] = CHAR_NULL;
508
509 PrintLine2 = AllocatePool (BufLen * 2);
510 if (PrintLine2 != NULL) {
511 ShellCopySearchAndReplace(PrintLine, PrintLine2, BufLen * 2, L"%", L"^%", FALSE, FALSE);
512
513 ShellPrintEx (
514 0,
515 (INT32)Row - 1,
516 L"%s",
517 PrintLine2
518 );
519 FreePool (PrintLine2);
520 }
521 FreePool (PrintLine);
522 }
523
524 return EFI_SUCCESS;
525 }
526
527 /**
528 Set the cursor position according to FileBuffer.DisplayPosition.
529
530 @retval EFI_SUCCESS The operation was successful.
531 **/
532 EFI_STATUS
533 FileBufferRestorePosition (
534 VOID
535 )
536 {
537 //
538 // set cursor position
539 //
540 return (gST->ConOut->SetCursorPosition (
541 gST->ConOut,
542 FileBuffer.DisplayPosition.Column - 1,
543 FileBuffer.DisplayPosition.Row - 1
544 ));
545 }
546
547 /**
548 Refresh the screen with whats in the buffer.
549
550 @retval EFI_SUCCESS The refresh was successful.
551 @retval EFI_LOAD_ERROR There was an error finding what to write.
552 **/
553 EFI_STATUS
554 FileBufferRefresh (
555 VOID
556 )
557 {
558 LIST_ENTRY *Link;
559 EFI_EDITOR_LINE *Line;
560 UINTN Row;
561
562 //
563 // if it's the first time after editor launch, so should refresh
564 //
565 if (!EditorFirst) {
566 //
567 // no definite required refresh
568 // and file position displayed on screen has not been changed
569 //
570 if (!FileBufferNeedRefresh &&
571 !FileBufferOnlyLineNeedRefresh &&
572 FileBufferBackupVar.LowVisibleRange.Row == FileBuffer.LowVisibleRange.Row &&
573 FileBufferBackupVar.LowVisibleRange.Column == FileBuffer.LowVisibleRange.Column
574 ) {
575
576 FileBufferRestoreMousePosition ();
577 FileBufferRestorePosition ();
578
579 return EFI_SUCCESS;
580 }
581 }
582
583 gST->ConOut->EnableCursor (gST->ConOut, FALSE);
584
585 //
586 // only need to refresh current line
587 //
588 if (FileBufferOnlyLineNeedRefresh &&
589 FileBufferBackupVar.LowVisibleRange.Row == FileBuffer.LowVisibleRange.Row &&
590 FileBufferBackupVar.LowVisibleRange.Column == FileBuffer.LowVisibleRange.Column
591 ) {
592
593 EditorClearLine (FileBuffer.DisplayPosition.Row, MainEditor.ScreenSize.Column, MainEditor.ScreenSize.Row);
594 FileBufferPrintLine (
595 FileBuffer.CurrentLine,
596 FileBuffer.DisplayPosition.Row
597 );
598 } else {
599 //
600 // the whole edit area need refresh
601 //
602
603 //
604 // no line
605 //
606 if (FileBuffer.Lines == NULL) {
607 FileBufferRestoreMousePosition ();
608 FileBufferRestorePosition ();
609 gST->ConOut->EnableCursor (gST->ConOut, TRUE);
610
611 return EFI_SUCCESS;
612 }
613 //
614 // get the first line that will be displayed
615 //
616 Line = MoveLine (FileBuffer.LowVisibleRange.Row - FileBuffer.FilePosition.Row);
617 if (Line == NULL) {
618 gST->ConOut->EnableCursor (gST->ConOut, TRUE);
619
620 return EFI_LOAD_ERROR;
621 }
622
623 Link = &(Line->Link);
624 Row = 2;
625 do {
626 Line = CR (Link, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE);
627
628 //
629 // print line at row
630 //
631 FileBufferPrintLine (Line, Row);
632
633 Link = Link->ForwardLink;
634 Row++;
635 } while (Link != FileBuffer.ListHead && Row <= (MainEditor.ScreenSize.Row - 1));
636 //
637 // while not file end and not screen full
638 //
639 while (Row <= (MainEditor.ScreenSize.Row - 1)) {
640 EditorClearLine (Row, MainEditor.ScreenSize.Column, MainEditor.ScreenSize.Row);
641 Row++;
642 }
643 }
644
645 FileBufferRestoreMousePosition ();
646 FileBufferRestorePosition ();
647
648 FileBufferNeedRefresh = FALSE;
649 FileBufferOnlyLineNeedRefresh = FALSE;
650
651 gST->ConOut->EnableCursor (gST->ConOut, TRUE);
652 return EFI_SUCCESS;
653 }
654
655 /**
656 Create a new line and append it to the line list.
657 Fields affected:
658 NumLines
659 Lines
660
661 @retval NULL The create line failed.
662 @return The line created.
663 **/
664 EFI_EDITOR_LINE *
665 FileBufferCreateLine (
666 VOID
667 )
668 {
669 EFI_EDITOR_LINE *Line;
670
671 //
672 // allocate a line structure
673 //
674 Line = AllocateZeroPool (sizeof (EFI_EDITOR_LINE));
675 if (Line == NULL) {
676 return NULL;
677 }
678 //
679 // initialize the structure
680 //
681 Line->Signature = LINE_LIST_SIGNATURE;
682 Line->Size = 0;
683 Line->TotalSize = 0;
684 Line->Type = NewLineTypeDefault;
685
686 //
687 // initial buffer of the line is "\0"
688 //
689 ASSERT(CHAR_NULL == CHAR_NULL);
690 Line->Buffer = CatSPrint (NULL, L"\0");
691 if (Line->Buffer == NULL) {
692 return NULL;
693 }
694
695 FileBuffer.NumLines++;
696
697 //
698 // insert the line into line list
699 //
700 InsertTailList (FileBuffer.ListHead, &Line->Link);
701
702 if (FileBuffer.Lines == NULL) {
703 FileBuffer.Lines = CR (FileBuffer.ListHead->ForwardLink, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE);
704 }
705
706 return Line;
707 }
708
709 /**
710 Set FileName field in FileBuffer.
711
712 @param Str The file name to set.
713
714 @retval EFI_SUCCESS The filename was successfully set.
715 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
716 @retval EFI_INVALID_PARAMETER Str is not a valid filename.
717 **/
718 EFI_STATUS
719 FileBufferSetFileName (
720 IN CONST CHAR16 *Str
721 )
722 {
723 //
724 // Verify the parameters
725 //
726 if (!IsValidFileName(Str)) {
727 return (EFI_INVALID_PARAMETER);
728 }
729 //
730 // free the old file name
731 //
732 SHELL_FREE_NON_NULL (FileBuffer.FileName);
733
734 //
735 // Allocate and set the new name
736 //
737 FileBuffer.FileName = CatSPrint (NULL, L"%s", Str);
738 if (FileBuffer.FileName == NULL) {
739 return EFI_OUT_OF_RESOURCES;
740 }
741
742 return EFI_SUCCESS;
743 }
744 /**
745 Free the existing file lines and reset the modified flag.
746
747 @retval EFI_SUCCESS The operation was successful.
748 **/
749 EFI_STATUS
750 FileBufferFree (
751 VOID
752 )
753 {
754 //
755 // free all the lines
756 //
757 FileBufferFreeLines ();
758 FileBuffer.FileModified = FALSE;
759
760 return EFI_SUCCESS;
761 }
762
763
764 /**
765 Read a file from disk into the FileBuffer.
766
767 @param[in] FileName The filename to read.
768 @param[in] Recover TRUE if is for recover mode, no information printouts.
769
770 @retval EFI_SUCCESS The load was successful.
771 @retval EFI_LOAD_ERROR The load failed.
772 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
773 @retval EFI_INVALID_PARAMETER FileName is a directory.
774 **/
775 EFI_STATUS
776 FileBufferRead (
777 IN CONST CHAR16 *FileName,
778 IN CONST BOOLEAN Recover
779 )
780 {
781 EFI_EDITOR_LINE *Line;
782 EE_NEWLINE_TYPE Type;
783 UINTN LoopVar1;
784 UINTN LoopVar2;
785 UINTN LineSize;
786 VOID *Buffer;
787 CHAR16 *UnicodeBuffer;
788 UINT8 *AsciiBuffer;
789 UINTN FileSize;
790 SHELL_FILE_HANDLE FileHandle;
791 BOOLEAN CreateFile;
792 EFI_STATUS Status;
793 UINTN LineSizeBackup;
794 EFI_FILE_INFO *Info;
795
796 Line = NULL;
797 LoopVar1 = 0;
798 FileSize = 0;
799 UnicodeBuffer = NULL;
800 Type = NewLineTypeDefault;
801 FileHandle = NULL;
802 CreateFile = FALSE;
803
804 //
805 // in this function, when you return error ( except EFI_OUT_OF_RESOURCES )
806 // you should set status string via StatusBarSetStatusString(L"blah")
807 // since this function maybe called before the editorhandleinput loop
808 // so any error will cause editor return
809 // so if you want to print the error status
810 // you should set the status string
811 //
812
813 //
814 // try to open the file
815 //
816 Status = ShellOpenFileByName (FileName, &FileHandle, EFI_FILE_MODE_READ, 0);
817
818 if (!EFI_ERROR(Status)) {
819 CreateFile = FALSE;
820 if (FileHandle == NULL) {
821 StatusBarSetStatusString (L"Disk Error");
822 return EFI_LOAD_ERROR;
823 }
824
825 Info = ShellGetFileInfo(FileHandle);
826
827 if (Info->Attribute & EFI_FILE_DIRECTORY) {
828 StatusBarSetStatusString (L"Directory Can Not Be Edited");
829 FreePool (Info);
830 return EFI_INVALID_PARAMETER;
831 }
832
833 if (Info->Attribute & EFI_FILE_READ_ONLY) {
834 FileBuffer.ReadOnly = TRUE;
835 } else {
836 FileBuffer.ReadOnly = FALSE;
837 }
838 //
839 // get file size
840 //
841 FileSize = (UINTN) Info->FileSize;
842
843 FreePool (Info);
844 } else if (Status == EFI_NOT_FOUND) {
845 //
846 // file not exists. add create and try again
847 //
848 Status = ShellOpenFileByName (FileName, &FileHandle, EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE|EFI_FILE_MODE_CREATE, 0);
849 if (EFI_ERROR (Status)) {
850 if (Status == EFI_WRITE_PROTECTED ||
851 Status == EFI_ACCESS_DENIED ||
852 Status == EFI_NO_MEDIA ||
853 Status == EFI_MEDIA_CHANGED
854 ) {
855 StatusBarSetStatusString (L"Access Denied");
856 } else if (Status == EFI_DEVICE_ERROR || Status == EFI_VOLUME_CORRUPTED || Status == EFI_VOLUME_FULL) {
857 StatusBarSetStatusString (L"Disk Error");
858 } else {
859 StatusBarSetStatusString (L"Invalid File Name or Current-working-directory");
860 }
861
862 return Status;
863 } else {
864 //
865 // it worked. now delete it and move on with the name (now validated)
866 //
867 Status = ShellDeleteFile (&FileHandle);
868 if (Status == EFI_WARN_DELETE_FAILURE) {
869 Status = EFI_ACCESS_DENIED;
870 }
871 FileHandle = NULL;
872 if (EFI_ERROR (Status)) {
873 StatusBarSetStatusString (L"Access Denied");
874 return Status;
875 }
876 }
877 //
878 // file doesn't exist, so set CreateFile to TRUE
879 //
880 CreateFile = TRUE;
881 FileBuffer.ReadOnly = FALSE;
882
883 //
884 // all the check ends
885 // so now begin to set file name, free lines
886 //
887 if (StrCmp (FileName, FileBuffer.FileName) != 0) {
888 FileBufferSetFileName (FileName);
889 }
890 //
891 // free the old lines
892 //
893 FileBufferFree ();
894
895 }
896 //
897 // the file exists
898 //
899 if (!CreateFile) {
900 //
901 // allocate buffer to read file
902 //
903 Buffer = AllocateZeroPool (FileSize);
904 if (Buffer == NULL) {
905 return EFI_OUT_OF_RESOURCES;
906 }
907 //
908 // read file into Buffer
909 //
910 Status = ShellReadFile (FileHandle, &FileSize, Buffer);
911 ShellCloseFile(&FileHandle);
912 FileHandle = NULL;
913 if (EFI_ERROR (Status)) {
914 StatusBarSetStatusString (L"Read File Failed");
915 SHELL_FREE_NON_NULL (Buffer);
916 return EFI_LOAD_ERROR;
917 }
918 //
919 // nothing in this file
920 //
921 if (FileSize == 0) {
922 SHELL_FREE_NON_NULL (Buffer);
923 //
924 // since has no head, so only can be an ASCII file
925 //
926 FileBuffer.FileType = FileTypeAscii;
927
928 goto Done;
929 }
930
931 AsciiBuffer = Buffer;
932
933 if (FileSize < 2) {
934 //
935 // size < Unicode file header, so only can be ASCII file
936 //
937 FileBuffer.FileType = FileTypeAscii;
938 } else {
939 //
940 // Unicode file
941 //
942 if (*(UINT16 *) Buffer == EFI_UNICODE_BYTE_ORDER_MARK) {
943 //
944 // Unicode file's size should be even
945 //
946 if ((FileSize % 2) != 0) {
947 StatusBarSetStatusString (L"File Format Wrong");
948 SHELL_FREE_NON_NULL (Buffer);
949 return EFI_LOAD_ERROR;
950 }
951
952 FileSize /= 2;
953
954 FileBuffer.FileType = FileTypeUnicode;
955 UnicodeBuffer = Buffer;
956
957 //
958 // pass this 0xff and 0xfe
959 //
960 UnicodeBuffer++;
961 FileSize--;
962 } else {
963 FileBuffer.FileType = FileTypeAscii;
964 }
965 //
966 // end of AsciiBuffer ==
967 //
968 }
969 //
970 // end of FileSize < 2
971 // all the check ends
972 // so now begin to set file name, free lines
973 //
974 if (StrCmp (FileName, FileBuffer.FileName) != 0) {
975 FileBufferSetFileName (FileName);
976 }
977
978 //
979 // free the old lines
980 //
981 FileBufferFree ();
982
983 //
984 // parse file content line by line
985 //
986 for (LoopVar1 = 0; LoopVar1 < FileSize; LoopVar1++) {
987 Type = NewLineTypeUnknown;
988
989 for (LineSize = LoopVar1; LineSize < FileSize; LineSize++) {
990 if (FileBuffer.FileType == FileTypeAscii) {
991 if (AsciiBuffer[LineSize] == CHAR_CARRIAGE_RETURN) {
992 Type = NewLineTypeCarriageReturn;
993
994 //
995 // has LF following
996 //
997 if (LineSize < FileSize - 1) {
998 if (AsciiBuffer[LineSize + 1] == CHAR_LINEFEED) {
999 Type = NewLineTypeCarriageReturnLineFeed;
1000 }
1001 }
1002
1003 break;
1004 } else if (AsciiBuffer[LineSize] == CHAR_LINEFEED) {
1005 Type = NewLineTypeLineFeed;
1006
1007 //
1008 // has CR following
1009 //
1010 if (LineSize < FileSize - 1) {
1011 if (AsciiBuffer[LineSize + 1] == CHAR_CARRIAGE_RETURN) {
1012 Type = NewLineTypeLineFeedCarriageReturn;
1013 }
1014 }
1015
1016 break;
1017 }
1018 } else {
1019 if (UnicodeBuffer[LineSize] == CHAR_CARRIAGE_RETURN) {
1020 Type = NewLineTypeCarriageReturn;
1021
1022 //
1023 // has LF following
1024 //
1025 if (LineSize < FileSize - 1) {
1026 if (UnicodeBuffer[LineSize + 1] == CHAR_LINEFEED) {
1027 Type = NewLineTypeCarriageReturnLineFeed;
1028 }
1029 }
1030
1031 break;
1032 } else if (UnicodeBuffer[LineSize] == CHAR_LINEFEED) {
1033 Type = NewLineTypeLineFeed;
1034
1035 //
1036 // has CR following
1037 //
1038 if (LineSize < FileSize - 1) {
1039 if (UnicodeBuffer[LineSize + 1] == CHAR_CARRIAGE_RETURN) {
1040 Type = NewLineTypeLineFeedCarriageReturn;
1041 }
1042 }
1043
1044 break;
1045 }
1046 }
1047 //
1048 // endif == ASCII
1049 //
1050 }
1051 //
1052 // end of for LineSize
1053 //
1054 // if the type is wrong, then exit
1055 //
1056 if (Type == NewLineTypeUnknown) {
1057 //
1058 // Now if Type is NewLineTypeUnknown, it should be file end
1059 //
1060 Type = NewLineTypeDefault;
1061 }
1062
1063 LineSizeBackup = LineSize;
1064
1065 //
1066 // create a new line
1067 //
1068 Line = FileBufferCreateLine ();
1069 if (Line == NULL) {
1070 SHELL_FREE_NON_NULL (Buffer);
1071 return EFI_OUT_OF_RESOURCES;
1072 }
1073 //
1074 // calculate file length
1075 //
1076 LineSize -= LoopVar1;
1077
1078 //
1079 // Unicode and one CHAR_NULL
1080 //
1081 SHELL_FREE_NON_NULL (Line->Buffer);
1082 Line->Buffer = AllocateZeroPool (LineSize * 2 + 2);
1083
1084 if (Line->Buffer == NULL) {
1085 RemoveEntryList (&Line->Link);
1086 return EFI_OUT_OF_RESOURCES;
1087 }
1088 //
1089 // copy this line to Line->Buffer
1090 //
1091 for (LoopVar2 = 0; LoopVar2 < LineSize; LoopVar2++) {
1092 if (FileBuffer.FileType == FileTypeAscii) {
1093 Line->Buffer[LoopVar2] = (CHAR16) AsciiBuffer[LoopVar1];
1094 } else {
1095 Line->Buffer[LoopVar2] = UnicodeBuffer[LoopVar1];
1096 }
1097
1098 LoopVar1++;
1099 }
1100 //
1101 // LoopVar1 now points to where CHAR_CARRIAGE_RETURN or CHAR_LINEFEED;
1102 //
1103 Line->Buffer[LineSize] = 0;
1104
1105 Line->Size = LineSize;
1106 Line->TotalSize = LineSize;
1107 Line->Type = Type;
1108
1109 if (Type == NewLineTypeCarriageReturnLineFeed || Type == NewLineTypeLineFeedCarriageReturn) {
1110 LoopVar1++;
1111 }
1112
1113 //
1114 // last character is a return, SO create a new line
1115 //
1116 if (((Type == NewLineTypeCarriageReturnLineFeed || Type == NewLineTypeLineFeedCarriageReturn) && LineSizeBackup == FileSize - 2) ||
1117 ((Type == NewLineTypeLineFeed || Type == NewLineTypeCarriageReturn) && LineSizeBackup == FileSize - 1)
1118 ) {
1119 Line = FileBufferCreateLine ();
1120 if (Line == NULL) {
1121 SHELL_FREE_NON_NULL (Buffer);
1122 return EFI_OUT_OF_RESOURCES;
1123 }
1124 }
1125 //
1126 // end of if
1127 //
1128 }
1129 //
1130 // end of LoopVar1
1131 //
1132 SHELL_FREE_NON_NULL (Buffer);
1133
1134 }
1135 //
1136 // end of if CreateFile
1137 //
1138 Done:
1139
1140 FileBuffer.DisplayPosition.Row = 2;
1141 FileBuffer.DisplayPosition.Column = 1;
1142 FileBuffer.LowVisibleRange.Row = 1;
1143 FileBuffer.LowVisibleRange.Column = 1;
1144 FileBuffer.FilePosition.Row = 1;
1145 FileBuffer.FilePosition.Column = 1;
1146 FileBuffer.MousePosition.Row = 2;
1147 FileBuffer.MousePosition.Column = 1;
1148
1149 if (!Recover) {
1150 UnicodeBuffer = CatSPrint (NULL, L"%d Lines Read", FileBuffer.NumLines);
1151 if (UnicodeBuffer == NULL) {
1152 return EFI_OUT_OF_RESOURCES;
1153 }
1154
1155 StatusBarSetStatusString (UnicodeBuffer);
1156 FreePool (UnicodeBuffer);
1157 }
1158 /*
1159 //
1160 // check whether we have fs?: in filename
1161 //
1162 LoopVar1 = 0;
1163 FSMappingPtr = NULL;
1164 while (FileName[LoopVar1] != 0) {
1165 if (FileName[LoopVar1] == L':') {
1166 FSMappingPtr = &FileName[LoopVar1];
1167 break;
1168 }
1169
1170 LoopVar1++;
1171 }
1172
1173 if (FSMappingPtr == NULL) {
1174 CurDir = ShellGetCurrentDir (NULL);
1175 } else {
1176 LoopVar1 = 0;
1177 LoopVar2 = 0;
1178 while (FileName[LoopVar1] != 0) {
1179 if (FileName[LoopVar1] == L':') {
1180 break;
1181 }
1182
1183 FSMapping[LoopVar2++] = FileName[LoopVar1];
1184
1185 LoopVar1++;
1186 }
1187
1188 FSMapping[LoopVar2] = 0;
1189 CurDir = ShellGetCurrentDir (FSMapping);
1190 }
1191
1192 if (CurDir != NULL) {
1193 for (LoopVar1 = 0; LoopVar1 < StrLen (CurDir) && CurDir[LoopVar1] != ':'; LoopVar1++);
1194
1195 CurDir[LoopVar1] = 0;
1196 DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) ShellGetMap (CurDir);
1197 FreePool (CurDir);
1198 } else {
1199 return EFI_LOAD_ERROR;
1200 }
1201
1202 Status = LibDevicePathToInterface (
1203 &gEfiSimpleFileSystemProtocolGuid,
1204 DevicePath,
1205 (VOID **) &Vol
1206 );
1207 if (EFI_ERROR (Status)) {
1208 return EFI_LOAD_ERROR;
1209 }
1210
1211 Status = Vol->OpenVolume (Vol, &RootFs);
1212 if (EFI_ERROR (Status)) {
1213 return EFI_LOAD_ERROR;
1214 }
1215 //
1216 // Get volume information of file system
1217 //
1218 Size = SIZE_OF_EFI_FILE_SYSTEM_INFO + 100;
1219 VolumeInfo = (EFI_FILE_SYSTEM_INFO *) AllocateZeroPool (Size);
1220 Status = RootFs->GetInfo (RootFs, &gEfiFileSystemInfoGuid, &Size, VolumeInfo);
1221 if (EFI_ERROR (Status)) {
1222 RootFs->Close (RootFs);
1223 return EFI_LOAD_ERROR;
1224 }
1225
1226 if (VolumeInfo->ReadOnly) {
1227 StatusBarSetStatusString (L"WARNING: Volume Read Only");
1228 }
1229
1230 FreePool (VolumeInfo);
1231 RootFs->Close (RootFs);
1232 }
1233 //
1234 */
1235 //
1236 // has line
1237 //
1238 if (FileBuffer.Lines != 0) {
1239 FileBuffer.CurrentLine = CR (FileBuffer.ListHead->ForwardLink, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE);
1240 } else {
1241 //
1242 // create a dummy line
1243 //
1244 Line = FileBufferCreateLine ();
1245 if (Line == NULL) {
1246 return EFI_OUT_OF_RESOURCES;
1247 }
1248
1249 FileBuffer.CurrentLine = Line;
1250 }
1251
1252 FileBuffer.FileModified = FALSE;
1253 FileBufferNeedRefresh = TRUE;
1254 FileBufferOnlyLineNeedRefresh = FALSE;
1255 FileBufferMouseNeedRefresh = TRUE;
1256
1257
1258 return EFI_SUCCESS;
1259 }
1260
1261 /**
1262 According to FileBuffer.NewLineType & FileBuffer.FileType,
1263 get the return buffer and size.
1264
1265 @param[in] Type The type of line.
1266 @param[out] Buffer The buffer to fill.
1267 @param[out] Size The amount of the buffer used on return.
1268 **/
1269 VOID
1270 GetNewLine (
1271 IN CONST EE_NEWLINE_TYPE Type,
1272 OUT CHAR8 *Buffer,
1273 OUT UINT8 *Size
1274 )
1275 {
1276 UINT8 NewLineSize;
1277
1278 //
1279 // give new line buffer,
1280 // and will judge unicode or ascii
1281 //
1282 NewLineSize = 0;
1283
1284 //
1285 // not legal new line type
1286 //
1287 if (Type != NewLineTypeLineFeed && Type != NewLineTypeCarriageReturn && Type != NewLineTypeCarriageReturnLineFeed && Type != NewLineTypeLineFeedCarriageReturn) {
1288 *Size = 0;
1289 return ;
1290 }
1291 //
1292 // use_cr: give 0x0d
1293 //
1294 if (Type == NewLineTypeCarriageReturn) {
1295 if (MainEditor.FileBuffer->FileType == FileTypeUnicode) {
1296 Buffer[0] = 0x0d;
1297 Buffer[1] = 0;
1298 NewLineSize = 2;
1299 } else {
1300 Buffer[0] = 0x0d;
1301 NewLineSize = 1;
1302 }
1303
1304 *Size = NewLineSize;
1305 return ;
1306 }
1307 //
1308 // use_lf: give 0x0a
1309 //
1310 if (Type == NewLineTypeLineFeed) {
1311 if (MainEditor.FileBuffer->FileType == FileTypeUnicode) {
1312 Buffer[0] = 0x0a;
1313 Buffer[1] = 0;
1314 NewLineSize = 2;
1315 } else {
1316 Buffer[0] = 0x0a;
1317 NewLineSize = 1;
1318 }
1319
1320 *Size = NewLineSize;
1321 return ;
1322 }
1323 //
1324 // use_crlf: give 0x0d 0x0a
1325 //
1326 if (Type == NewLineTypeCarriageReturnLineFeed) {
1327 if (MainEditor.FileBuffer->FileType == FileTypeUnicode) {
1328 Buffer[0] = 0x0d;
1329 Buffer[1] = 0;
1330 Buffer[2] = 0x0a;
1331 Buffer[3] = 0;
1332
1333 NewLineSize = 4;
1334 } else {
1335 Buffer[0] = 0x0d;
1336 Buffer[1] = 0x0a;
1337 NewLineSize = 2;
1338 }
1339
1340 *Size = NewLineSize;
1341 return ;
1342 }
1343 //
1344 // use_lfcr: give 0x0a 0x0d
1345 //
1346 if (Type == NewLineTypeLineFeedCarriageReturn) {
1347 if (MainEditor.FileBuffer->FileType == FileTypeUnicode) {
1348 Buffer[0] = 0x0a;
1349 Buffer[1] = 0;
1350 Buffer[2] = 0x0d;
1351 Buffer[3] = 0;
1352
1353 NewLineSize = 4;
1354 } else {
1355 Buffer[0] = 0x0a;
1356 Buffer[1] = 0x0d;
1357 NewLineSize = 2;
1358 }
1359
1360 *Size = NewLineSize;
1361 return ;
1362 }
1363
1364 }
1365
1366 /**
1367 Change a Unicode string to an ASCII string.
1368
1369 @param[in] UStr The Unicode string.
1370 @param[in] Length The maximum size of AStr.
1371 @param[out] AStr ASCII string to pass out.
1372
1373 @return The actuall length.
1374 **/
1375 UINTN
1376 UnicodeToAscii (
1377 IN CONST CHAR16 *UStr,
1378 IN CONST UINTN Length,
1379 OUT CHAR8 *AStr
1380 )
1381 {
1382 UINTN Index;
1383
1384 //
1385 // just buffer copy, not character copy
1386 //
1387 for (Index = 0; Index < Length; Index++) {
1388 *AStr++ = (CHAR8) *UStr++;
1389 }
1390
1391 return Index;
1392 }
1393
1394 /**
1395 Save lines in FileBuffer to disk
1396
1397 @param[in] FileName The file name for writing.
1398
1399 @retval EFI_SUCCESS Data was written.
1400 @retval EFI_LOAD_ERROR
1401 @retval EFI_OUT_OF_RESOURCES There were not enough resources to write the file.
1402 **/
1403 EFI_STATUS
1404 FileBufferSave (
1405 IN CONST CHAR16 *FileName
1406 )
1407 {
1408 SHELL_FILE_HANDLE FileHandle;
1409 LIST_ENTRY *Link;
1410 EFI_EDITOR_LINE *Line;
1411 CHAR16 *Str;
1412
1413 EFI_STATUS Status;
1414 UINTN Length;
1415 UINTN NumLines;
1416 CHAR8 NewLineBuffer[4];
1417 UINT8 NewLineSize;
1418
1419 EFI_FILE_INFO *Info;
1420
1421 UINT64 Attribute;
1422
1423 EE_NEWLINE_TYPE Type;
1424
1425 UINTN TotalSize;
1426 //
1427 // 2M
1428 //
1429 CHAR8 *Cache;
1430 UINTN LeftSize;
1431 UINTN Size;
1432 CHAR8 *Ptr;
1433
1434 Length = 0;
1435 //
1436 // 2M
1437 //
1438 TotalSize = 0x200000;
1439
1440 Attribute = 0;
1441
1442
1443
1444 //
1445 // if is the old file
1446 //
1447 if (FileBuffer.FileName != NULL && StrCmp (FileName, FileBuffer.FileName) == 0) {
1448 //
1449 // file has not been modified
1450 //
1451 if (!FileBuffer.FileModified) {
1452 return EFI_SUCCESS;
1453 }
1454
1455 //
1456 // if file is read-only, set error
1457 //
1458 if (FileBuffer.ReadOnly) {
1459 StatusBarSetStatusString (L"Read Only File Can Not Be Saved");
1460 return EFI_SUCCESS;
1461 }
1462 }
1463
1464 Status = ShellOpenFileByName (FileName, &FileHandle, EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE, 0);
1465
1466 if (!EFI_ERROR (Status)) {
1467 Info = ShellGetFileInfo(FileHandle);
1468
1469 if (Info != NULL && Info->Attribute & EFI_FILE_DIRECTORY) {
1470 StatusBarSetStatusString (L"Directory Can Not Be Saved");
1471 ShellCloseFile(FileHandle);
1472 FreePool(Info);
1473 return EFI_LOAD_ERROR;
1474 }
1475
1476 if (Info != NULL) {
1477 Attribute = Info->Attribute & ~EFI_FILE_READ_ONLY;
1478 FreePool(Info);
1479 }
1480
1481 //
1482 // if file exits, so delete it
1483 //
1484 Status = ShellDeleteFile (&FileHandle);
1485 if (EFI_ERROR (Status) || Status == EFI_WARN_DELETE_FAILURE) {
1486 StatusBarSetStatusString (L"Write File Failed");
1487 return EFI_LOAD_ERROR;
1488 }
1489 }
1490
1491 Status = ShellOpenFileByName (FileName, &FileHandle, EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE|EFI_FILE_MODE_CREATE, Attribute);
1492
1493 if (EFI_ERROR (Status)) {
1494 StatusBarSetStatusString (L"Create File Failed");
1495 return EFI_LOAD_ERROR;
1496 }
1497
1498 //
1499 // if file is Unicode file, write Unicode header to it.
1500 //
1501 if (FileBuffer.FileType == FileTypeUnicode) {
1502 Length = 2;
1503 Status = ShellWriteFile (FileHandle, &Length, (VOID*)&gUnicodeFileTag);
1504 if (EFI_ERROR (Status)) {
1505 ShellDeleteFile (&FileHandle);
1506 return EFI_LOAD_ERROR;
1507 }
1508 }
1509
1510 Cache = AllocateZeroPool (TotalSize);
1511 if (Cache == NULL) {
1512 ShellDeleteFile (&FileHandle);
1513 return EFI_OUT_OF_RESOURCES;
1514 }
1515
1516 //
1517 // write all the lines back to disk
1518 //
1519 NumLines = 0;
1520 Type = NewLineTypeCarriageReturnLineFeed;
1521
1522 Ptr = Cache;
1523 LeftSize = TotalSize;
1524
1525 for (Link = FileBuffer.ListHead->ForwardLink; Link != FileBuffer.ListHead; Link = Link->ForwardLink) {
1526 Line = CR (Link, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE);
1527
1528 if (Line->Type != NewLineTypeDefault) {
1529 Type = Line->Type;
1530 }
1531 //
1532 // newline character is at most 4 bytes ( two Unicode characters )
1533 //
1534 Length = 4;
1535 if (Line->Buffer != NULL && Line->Size != 0) {
1536 if (FileBuffer.FileType == FileTypeAscii) {
1537 Length += Line->Size;
1538 } else {
1539 Length += (Line->Size * 2);
1540 }
1541 //
1542 // end if FileTypeAscii
1543 //
1544 }
1545
1546 //
1547 // no cache room left, so write cache to disk
1548 //
1549 if (LeftSize < Length) {
1550 Size = TotalSize - LeftSize;
1551 Status = ShellWriteFile (FileHandle, &Size, Cache);
1552 if (EFI_ERROR (Status)) {
1553 ShellDeleteFile (&FileHandle);
1554 FreePool (Cache);
1555 return EFI_LOAD_ERROR;
1556 }
1557 Ptr = Cache;
1558 LeftSize = TotalSize;
1559 }
1560
1561 if (Line->Buffer != NULL && Line->Size != 0) {
1562 if (FileBuffer.FileType == FileTypeAscii) {
1563 UnicodeToAscii (Line->Buffer, Line->Size, Ptr);
1564 Length = Line->Size;
1565 } else {
1566 Length = (Line->Size * 2);
1567 CopyMem (Ptr, (CHAR8 *) Line->Buffer, Length);
1568 }
1569 //
1570 // end if FileTypeAscii
1571 //
1572 Ptr += Length;
1573 LeftSize -= Length;
1574
1575 }
1576 //
1577 // end of if Line -> Buffer != NULL && Line -> Size != 0
1578 //
1579 // if not the last line , write return buffer to disk
1580 //
1581 if (Link->ForwardLink != FileBuffer.ListHead) {
1582 GetNewLine (Type, NewLineBuffer, &NewLineSize);
1583 CopyMem (Ptr, (CHAR8 *) NewLineBuffer, NewLineSize);
1584
1585 Ptr += NewLineSize;
1586 LeftSize -= NewLineSize;
1587 }
1588
1589 NumLines++;
1590 }
1591
1592 if (TotalSize != LeftSize) {
1593 Size = TotalSize - LeftSize;
1594 Status = ShellWriteFile (FileHandle, &Size, Cache);
1595 if (EFI_ERROR (Status)) {
1596 ShellDeleteFile (&FileHandle);
1597 FreePool (Cache);
1598 return EFI_LOAD_ERROR;
1599 }
1600 }
1601
1602 FreePool (Cache);
1603
1604 ShellCloseFile(&FileHandle);
1605
1606 FileBuffer.FileModified = FALSE;
1607
1608 //
1609 // set status string
1610 //
1611 Str = CatSPrint (NULL, L"%d Lines Wrote", NumLines);
1612 if (Str == NULL) {
1613 return EFI_OUT_OF_RESOURCES;
1614 }
1615
1616 StatusBarSetStatusString (Str);
1617 SHELL_FREE_NON_NULL (Str);
1618
1619 //
1620 // now everything is ready , you can set the new file name to filebuffer
1621 //
1622 if (FileName != NULL && FileBuffer.FileName != NULL && StrCmp (FileName, FileBuffer.FileName) != 0) {
1623 //
1624 // not the same
1625 //
1626 FileBufferSetFileName (FileName);
1627 if (FileBuffer.FileName == NULL) {
1628 ShellDeleteFile (&FileHandle);
1629 return EFI_OUT_OF_RESOURCES;
1630 }
1631 }
1632
1633 FileBuffer.ReadOnly = FALSE;
1634 return EFI_SUCCESS;
1635 }
1636
1637 /**
1638 Scroll cursor to left 1 character position.
1639
1640 @retval EFI_SUCCESS The operation was successful.
1641 **/
1642 EFI_STATUS
1643 FileBufferScrollLeft (
1644 VOID
1645 )
1646 {
1647 EFI_EDITOR_LINE *Line;
1648 UINTN FRow;
1649 UINTN FCol;
1650
1651 Line = FileBuffer.CurrentLine;
1652
1653 FRow = FileBuffer.FilePosition.Row;
1654 FCol = FileBuffer.FilePosition.Column;
1655
1656 //
1657 // if already at start of this line, so move to the end of previous line
1658 //
1659 if (FCol <= 1) {
1660 //
1661 // has previous line
1662 //
1663 if (Line->Link.BackLink != FileBuffer.ListHead) {
1664 FRow--;
1665 Line = CR (Line->Link.BackLink, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE);
1666 FCol = Line->Size + 1;
1667 } else {
1668 return EFI_SUCCESS;
1669 }
1670 } else {
1671 //
1672 // if not at start of this line, just move to previous column
1673 //
1674 FCol--;
1675 }
1676
1677 FileBufferMovePosition (FRow, FCol);
1678
1679 return EFI_SUCCESS;
1680 }
1681
1682 /**
1683 Delete a char in line
1684
1685 @param[in, out] Line The line to delete in.
1686 @param[in] Pos Position to delete the char at ( start from 0 ).
1687 **/
1688 VOID
1689 LineDeleteAt (
1690 IN OUT EFI_EDITOR_LINE *Line,
1691 IN UINTN Pos
1692 )
1693 {
1694 UINTN Index;
1695
1696 //
1697 // move the latter characters front
1698 //
1699 for (Index = Pos - 1; Index < Line->Size; Index++) {
1700 Line->Buffer[Index] = Line->Buffer[Index + 1];
1701 }
1702
1703 Line->Size--;
1704 }
1705
1706 /**
1707 Concatenate Src into Dest.
1708
1709 @param[in, out] Dest Destination string
1710 @param[in] Src Src String.
1711 **/
1712 VOID
1713 LineCat (
1714 IN OUT EFI_EDITOR_LINE *Dest,
1715 IN EFI_EDITOR_LINE *Src
1716 )
1717 {
1718 CHAR16 *Str;
1719 UINTN Size;
1720
1721 Size = Dest->Size;
1722
1723 Dest->Buffer[Size] = 0;
1724
1725 //
1726 // concatenate the two strings
1727 //
1728 Str = CatSPrint (NULL, L"%s%s", Dest->Buffer, Src->Buffer);
1729 if (Str == NULL) {
1730 Dest->Buffer = NULL;
1731 return ;
1732 }
1733
1734 Dest->Size = Size + Src->Size;
1735 Dest->TotalSize = Dest->Size;
1736
1737 FreePool (Dest->Buffer);
1738 FreePool (Src->Buffer);
1739
1740 //
1741 // put str to dest->buffer
1742 //
1743 Dest->Buffer = Str;
1744 }
1745
1746 /**
1747 Delete the previous character.
1748
1749 @retval EFI_SUCCESS The delete was successful.
1750 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
1751 **/
1752 EFI_STATUS
1753 FileBufferDoBackspace (
1754 VOID
1755 )
1756 {
1757 EFI_EDITOR_LINE *Line;
1758 EFI_EDITOR_LINE *End;
1759 LIST_ENTRY *Link;
1760 UINTN FileColumn;
1761
1762 FileColumn = FileBuffer.FilePosition.Column;
1763
1764 Line = FileBuffer.CurrentLine;
1765
1766 //
1767 // the first column
1768 //
1769 if (FileColumn == 1) {
1770 //
1771 // the first row
1772 //
1773 if (FileBuffer.FilePosition.Row == 1) {
1774 return EFI_SUCCESS;
1775 }
1776
1777 FileBufferScrollLeft ();
1778
1779 Line = FileBuffer.CurrentLine;
1780 Link = Line->Link.ForwardLink;
1781 End = CR (Link, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE);
1782
1783 //
1784 // concatenate this line with previous line
1785 //
1786 LineCat (Line, End);
1787 if (Line->Buffer == NULL) {
1788 return EFI_OUT_OF_RESOURCES;
1789 }
1790 //
1791 // remove End from line list
1792 //
1793 RemoveEntryList (&End->Link);
1794 FreePool (End);
1795
1796 FileBuffer.NumLines--;
1797
1798 FileBufferNeedRefresh = TRUE;
1799 FileBufferOnlyLineNeedRefresh = FALSE;
1800
1801 } else {
1802 //
1803 // just delete the previous character
1804 //
1805 LineDeleteAt (Line, FileColumn - 1);
1806 FileBufferScrollLeft ();
1807 FileBufferOnlyLineNeedRefresh = TRUE;
1808 }
1809
1810 if (!FileBuffer.FileModified) {
1811 FileBuffer.FileModified = TRUE;
1812 }
1813
1814 return EFI_SUCCESS;
1815 }
1816
1817 /**
1818 Add a return into line at current position.
1819
1820 @retval EFI_SUCCESS The insetrion of the character was successful.
1821 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
1822 **/
1823 EFI_STATUS
1824 FileBufferDoReturn (
1825 VOID
1826 )
1827 {
1828 EFI_EDITOR_LINE *Line;
1829 EFI_EDITOR_LINE *NewLine;
1830 UINTN FileColumn;
1831 UINTN Index;
1832 CHAR16 *Buffer;
1833 UINTN Row;
1834 UINTN Col;
1835
1836 FileBufferNeedRefresh = TRUE;
1837 FileBufferOnlyLineNeedRefresh = FALSE;
1838
1839 Line = FileBuffer.CurrentLine;
1840
1841 FileColumn = FileBuffer.FilePosition.Column;
1842
1843 NewLine = AllocateZeroPool (sizeof (EFI_EDITOR_LINE));
1844 if (NewLine == NULL) {
1845 return EFI_OUT_OF_RESOURCES;
1846 }
1847
1848 NewLine->Signature = LINE_LIST_SIGNATURE;
1849 NewLine->Size = Line->Size - FileColumn + 1;
1850 NewLine->TotalSize = NewLine->Size;
1851 NewLine->Buffer = CatSPrint (NULL, L"\0");
1852 if (NewLine->Buffer == NULL) {
1853 return EFI_OUT_OF_RESOURCES;
1854 }
1855
1856 NewLine->Type = NewLineTypeDefault;
1857
1858 if (NewLine->Size > 0) {
1859 //
1860 // UNICODE + CHAR_NULL
1861 //
1862 Buffer = AllocateZeroPool (2 * (NewLine->Size + 1));
1863 if (Buffer == NULL) {
1864 FreePool (NewLine->Buffer);
1865 FreePool (NewLine);
1866 return EFI_OUT_OF_RESOURCES;
1867 }
1868
1869 FreePool (NewLine->Buffer);
1870
1871 NewLine->Buffer = Buffer;
1872
1873 for (Index = 0; Index < NewLine->Size; Index++) {
1874 NewLine->Buffer[Index] = Line->Buffer[Index + FileColumn - 1];
1875 }
1876
1877 NewLine->Buffer[NewLine->Size] = CHAR_NULL;
1878
1879 Line->Buffer[FileColumn - 1] = CHAR_NULL;
1880 Line->Size = FileColumn - 1;
1881 }
1882 //
1883 // increase NumLines
1884 //
1885 FileBuffer.NumLines++;
1886
1887 //
1888 // insert it into the correct position of line list
1889 //
1890 NewLine->Link.BackLink = &(Line->Link);
1891 NewLine->Link.ForwardLink = Line->Link.ForwardLink;
1892 Line->Link.ForwardLink->BackLink = &(NewLine->Link);
1893 Line->Link.ForwardLink = &(NewLine->Link);
1894
1895 //
1896 // move cursor to the start of next line
1897 //
1898 Row = FileBuffer.FilePosition.Row + 1;
1899 Col = 1;
1900
1901 FileBufferMovePosition (Row, Col);
1902
1903 //
1904 // set file is modified
1905 //
1906 if (!FileBuffer.FileModified) {
1907 FileBuffer.FileModified = TRUE;
1908 }
1909
1910 return EFI_SUCCESS;
1911 }
1912
1913 /**
1914 Delete current character from current line. This is the effect caused
1915 by the 'del' key.
1916
1917 @retval EFI_SUCCESS
1918 **/
1919 EFI_STATUS
1920 FileBufferDoDelete (
1921 VOID
1922 )
1923 {
1924 EFI_EDITOR_LINE *Line;
1925 EFI_EDITOR_LINE *Next;
1926 LIST_ENTRY *Link;
1927 UINTN FileColumn;
1928
1929 Line = FileBuffer.CurrentLine;
1930 FileColumn = FileBuffer.FilePosition.Column;
1931
1932 //
1933 // the last column
1934 //
1935 if (FileColumn >= Line->Size + 1) {
1936 //
1937 // the last line
1938 //
1939 if (Line->Link.ForwardLink == FileBuffer.ListHead) {
1940 return EFI_SUCCESS;
1941 }
1942 //
1943 // since last character,
1944 // so will add the next line to this line
1945 //
1946 Link = Line->Link.ForwardLink;
1947 Next = CR (Link, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE);
1948 LineCat (Line, Next);
1949 if (Line->Buffer == NULL) {
1950 return EFI_OUT_OF_RESOURCES;
1951 }
1952
1953 RemoveEntryList (&Next->Link);
1954 FreePool (Next);
1955
1956 FileBuffer.NumLines--;
1957
1958 FileBufferNeedRefresh = TRUE;
1959 FileBufferOnlyLineNeedRefresh = FALSE;
1960
1961 } else {
1962 //
1963 // just delete current character
1964 //
1965 LineDeleteAt (Line, FileColumn);
1966 FileBufferOnlyLineNeedRefresh = TRUE;
1967 }
1968
1969 if (!FileBuffer.FileModified) {
1970 FileBuffer.FileModified = TRUE;
1971 }
1972
1973 return EFI_SUCCESS;
1974 }
1975
1976 /**
1977 Scroll cursor to right 1 character.
1978
1979 @retval EFI_SUCCESS The operation was successful.
1980 **/
1981 EFI_STATUS
1982 FileBufferScrollRight (
1983 VOID
1984 )
1985 {
1986 EFI_EDITOR_LINE *Line;
1987 UINTN FRow;
1988 UINTN FCol;
1989
1990 Line = FileBuffer.CurrentLine;
1991 if (Line->Buffer == NULL) {
1992 return EFI_SUCCESS;
1993 }
1994
1995 FRow = FileBuffer.FilePosition.Row;
1996 FCol = FileBuffer.FilePosition.Column;
1997
1998 //
1999 // if already at end of this line, scroll it to the start of next line
2000 //
2001 if (FCol > Line->Size) {
2002 //
2003 // has next line
2004 //
2005 if (Line->Link.ForwardLink != FileBuffer.ListHead) {
2006 FRow++;
2007 FCol = 1;
2008 } else {
2009 return EFI_SUCCESS;
2010 }
2011 } else {
2012 //
2013 // if not at end of this line, just move to next column
2014 //
2015 FCol++;
2016 }
2017
2018 FileBufferMovePosition (FRow, FCol);
2019
2020 return EFI_SUCCESS;
2021 }
2022
2023 /**
2024 Insert a char into line
2025
2026
2027 @param[in] Line The line to insert into.
2028 @param[in] Char The char to insert.
2029 @param[in] Pos The position to insert the char at ( start from 0 ).
2030 @param[in] StrSize The current string size ( include CHAR_NULL ),unit is Unicode character.
2031
2032 @return The new string size ( include CHAR_NULL ) ( unit is Unicode character ).
2033 **/
2034 UINTN
2035 LineStrInsert (
2036 IN EFI_EDITOR_LINE *Line,
2037 IN CHAR16 Char,
2038 IN UINTN Pos,
2039 IN UINTN StrSize
2040 )
2041 {
2042 UINTN Index;
2043 CHAR16 *TempStringPtr;
2044 CHAR16 *Str;
2045
2046 Index = (StrSize) * 2;
2047
2048 Str = Line->Buffer;
2049
2050 //
2051 // do not have free space
2052 //
2053 if (Line->TotalSize <= Line->Size) {
2054 Str = ReallocatePool (Index, Index + 16, Str);
2055 if (Str == NULL) {
2056 return 0;
2057 }
2058
2059 Line->TotalSize += 8;
2060 }
2061 //
2062 // move the later part of the string one character right
2063 //
2064 TempStringPtr = Str;
2065 for (Index = StrSize; Index > Pos; Index--) {
2066 TempStringPtr[Index] = TempStringPtr[Index - 1];
2067 }
2068 //
2069 // insert char into it.
2070 //
2071 TempStringPtr[Index] = Char;
2072
2073 Line->Buffer = Str;
2074 Line->Size++;
2075
2076 return StrSize + 1;
2077 }
2078
2079 /**
2080 Add a character to the current line.
2081
2082 @param[in] Char The Character to input.
2083
2084 @retval EFI_SUCCESS The input was succesful.
2085 **/
2086 EFI_STATUS
2087 FileBufferAddChar (
2088 IN CHAR16 Char
2089 )
2090 {
2091 EFI_EDITOR_LINE *Line;
2092 UINTN FilePos;
2093
2094 Line = FileBuffer.CurrentLine;
2095
2096 //
2097 // only needs to refresh current line
2098 //
2099 FileBufferOnlyLineNeedRefresh = TRUE;
2100
2101 //
2102 // when is insert mode, or cursor is at end of this line,
2103 // so insert this character
2104 // or replace the character.
2105 //
2106 FilePos = FileBuffer.FilePosition.Column - 1;
2107 if (FileBuffer.ModeInsert || FilePos + 1 > Line->Size) {
2108 LineStrInsert (Line, Char, FilePos, Line->Size + 1);
2109 } else {
2110 Line->Buffer[FilePos] = Char;
2111 }
2112 //
2113 // move cursor to right
2114 //
2115 FileBufferScrollRight ();
2116
2117 if (!FileBuffer.FileModified) {
2118 FileBuffer.FileModified = TRUE;
2119 }
2120
2121 return EFI_SUCCESS;
2122 }
2123
2124 /**
2125 Handles inputs from characters (ASCII key + Backspace + return)
2126
2127 @param[in] Char The input character.
2128
2129 @retval EFI_SUCCESS The operation was successful.
2130 @retval EFI_LOAD_ERROR There was an error.
2131 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
2132 **/
2133 EFI_STATUS
2134 FileBufferDoCharInput (
2135 IN CONST CHAR16 Char
2136 )
2137 {
2138 EFI_STATUS Status;
2139
2140 Status = EFI_SUCCESS;
2141
2142 switch (Char) {
2143 case CHAR_NULL:
2144 break;
2145
2146 case CHAR_BACKSPACE:
2147 Status = FileBufferDoBackspace ();
2148 break;
2149
2150 case CHAR_TAB:
2151 //
2152 // Tabs are ignored
2153 //
2154 break;
2155
2156 case CHAR_LINEFEED:
2157 case CHAR_CARRIAGE_RETURN:
2158 Status = FileBufferDoReturn ();
2159 break;
2160
2161 default:
2162 //
2163 // DEAL WITH ASCII CHAR, filter out thing like ctrl+f
2164 //
2165 if (Char > 127 || Char < 32) {
2166 Status = StatusBarSetStatusString (L"Unknown Command");
2167 } else {
2168 Status = FileBufferAddChar (Char);
2169 }
2170
2171 break;
2172
2173 }
2174
2175 return Status;
2176 }
2177
2178 /**
2179 Scroll cursor to the next line.
2180
2181 @retval EFI_SUCCESS The operation was successful.
2182 **/
2183 EFI_STATUS
2184 FileBufferScrollDown (
2185 VOID
2186 )
2187 {
2188 EFI_EDITOR_LINE *Line;
2189 UINTN FRow;
2190 UINTN FCol;
2191
2192 Line = FileBuffer.CurrentLine;
2193 if (Line->Buffer == NULL) {
2194 return EFI_SUCCESS;
2195 }
2196
2197 FRow = FileBuffer.FilePosition.Row;
2198 FCol = FileBuffer.FilePosition.Column;
2199
2200 //
2201 // has next line
2202 //
2203 if (Line->Link.ForwardLink != FileBuffer.ListHead) {
2204 FRow++;
2205 Line = CR (Line->Link.ForwardLink, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE);
2206
2207 //
2208 // if the next line is not that long, so move to end of next line
2209 //
2210 if (FCol > Line->Size) {
2211 FCol = Line->Size + 1;
2212 }
2213
2214 } else {
2215 return EFI_SUCCESS;
2216 }
2217
2218 FileBufferMovePosition (FRow, FCol);
2219
2220 return EFI_SUCCESS;
2221 }
2222
2223 /**
2224 Scroll the cursor to previous line.
2225
2226 @retval EFI_SUCCESS The operation was successful.
2227 **/
2228 EFI_STATUS
2229 FileBufferScrollUp (
2230 VOID
2231 )
2232 {
2233 EFI_EDITOR_LINE *Line;
2234 UINTN FRow;
2235 UINTN FCol;
2236
2237 Line = FileBuffer.CurrentLine;
2238
2239 FRow = FileBuffer.FilePosition.Row;
2240 FCol = FileBuffer.FilePosition.Column;
2241
2242 //
2243 // has previous line
2244 //
2245 if (Line->Link.BackLink != FileBuffer.ListHead) {
2246 FRow--;
2247 Line = CR (Line->Link.BackLink, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE);
2248
2249 //
2250 // if previous line is not that long, so move to the end of previous line
2251 //
2252 if (FCol > Line->Size) {
2253 FCol = Line->Size + 1;
2254 }
2255
2256 } else {
2257 return EFI_SUCCESS;
2258 }
2259
2260 FileBufferMovePosition (FRow, FCol);
2261
2262 return EFI_SUCCESS;
2263 }
2264
2265 /**
2266 Scroll cursor to next page.
2267
2268 @retval EFI_SUCCESS The operation wa successful.
2269 **/
2270 EFI_STATUS
2271 FileBufferPageDown (
2272 VOID
2273 )
2274 {
2275 EFI_EDITOR_LINE *Line;
2276 UINTN FRow;
2277 UINTN FCol;
2278 UINTN Gap;
2279
2280 Line = FileBuffer.CurrentLine;
2281
2282 FRow = FileBuffer.FilePosition.Row;
2283 FCol = FileBuffer.FilePosition.Column;
2284
2285 //
2286 // has next page
2287 //
2288 if (FileBuffer.NumLines >= FRow + (MainEditor.ScreenSize.Row - 2)) {
2289 Gap = (MainEditor.ScreenSize.Row - 2);
2290 } else {
2291 //
2292 // MOVE CURSOR TO LAST LINE
2293 //
2294 Gap = FileBuffer.NumLines - FRow;
2295 }
2296 //
2297 // get correct line
2298 //
2299 Line = MoveLine (Gap);
2300
2301 //
2302 // if that line, is not that long, so move to the end of that line
2303 //
2304 if (Line != NULL && FCol > Line->Size) {
2305 FCol = Line->Size + 1;
2306 }
2307
2308 FRow += Gap;
2309
2310 FileBufferMovePosition (FRow, FCol);
2311
2312 return EFI_SUCCESS;
2313 }
2314
2315 /**
2316 Scroll cursor to previous screen.
2317
2318 @retval EFI_SUCCESS The operation was successful.
2319 **/
2320 EFI_STATUS
2321 FileBufferPageUp (
2322 VOID
2323 )
2324 {
2325 EFI_EDITOR_LINE *Line;
2326 UINTN FRow;
2327 UINTN FCol;
2328 UINTN Gap;
2329 INTN Retreat;
2330
2331 Line = FileBuffer.CurrentLine;
2332
2333 FRow = FileBuffer.FilePosition.Row;
2334 FCol = FileBuffer.FilePosition.Column;
2335
2336 //
2337 // has previous page
2338 //
2339 if (FRow > (MainEditor.ScreenSize.Row - 2)) {
2340 Gap = (MainEditor.ScreenSize.Row - 2);
2341 } else {
2342 //
2343 // the first line of file will displayed on the first line of screen
2344 //
2345 Gap = FRow - 1;
2346 }
2347
2348 Retreat = Gap;
2349 Retreat = -Retreat;
2350
2351 //
2352 // get correct line
2353 //
2354 Line = MoveLine (Retreat);
2355
2356 //
2357 // if that line is not that long, so move to the end of that line
2358 //
2359 if (Line != NULL && FCol > Line->Size) {
2360 FCol = Line->Size + 1;
2361 }
2362
2363 FRow -= Gap;
2364
2365 FileBufferMovePosition (FRow, FCol);
2366
2367 return EFI_SUCCESS;
2368 }
2369
2370 /**
2371 Scroll cursor to end of the current line.
2372
2373 @retval EFI_SUCCESS The operation was successful.
2374 **/
2375 EFI_STATUS
2376 FileBufferEnd (
2377 VOID
2378 )
2379 {
2380 EFI_EDITOR_LINE *Line;
2381 UINTN FRow;
2382 UINTN FCol;
2383
2384 Line = FileBuffer.CurrentLine;
2385
2386 FRow = FileBuffer.FilePosition.Row;
2387
2388 //
2389 // goto the last column of the line
2390 //
2391 FCol = Line->Size + 1;
2392
2393 FileBufferMovePosition (FRow, FCol);
2394
2395 return EFI_SUCCESS;
2396 }
2397
2398 /**
2399 Dispatch input to different handler
2400 @param[in] Key The input key. One of:
2401 ASCII KEY
2402 Backspace/Delete
2403 Return
2404 Direction key: up/down/left/right/pgup/pgdn
2405 Home/End
2406 INS
2407
2408 @retval EFI_SUCCESS The dispatch was done successfully.
2409 @retval EFI_LOAD_ERROR The dispatch was not successful.
2410 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
2411 **/
2412 EFI_STATUS
2413 FileBufferHandleInput (
2414 IN CONST EFI_INPUT_KEY *Key
2415 )
2416 {
2417 EFI_STATUS Status;
2418
2419 Status = EFI_SUCCESS;
2420
2421 switch (Key->ScanCode) {
2422 //
2423 // ordinary key input
2424 //
2425 case SCAN_NULL:
2426 if (!FileBuffer.ReadOnly) {
2427 Status = FileBufferDoCharInput (Key->UnicodeChar);
2428 } else {
2429 Status = StatusBarSetStatusString (L"Read Only File Can Not Be Modified");
2430 }
2431
2432 break;
2433
2434 //
2435 // up arrow
2436 //
2437 case SCAN_UP:
2438 Status = FileBufferScrollUp ();
2439 break;
2440
2441 //
2442 // down arrow
2443 //
2444 case SCAN_DOWN:
2445 Status = FileBufferScrollDown ();
2446 break;
2447
2448 //
2449 // right arrow
2450 //
2451 case SCAN_RIGHT:
2452 Status = FileBufferScrollRight ();
2453 break;
2454
2455 //
2456 // left arrow
2457 //
2458 case SCAN_LEFT:
2459 Status = FileBufferScrollLeft ();
2460 break;
2461
2462 //
2463 // page up
2464 //
2465 case SCAN_PAGE_UP:
2466 Status = FileBufferPageUp ();
2467 break;
2468
2469 //
2470 // page down
2471 //
2472 case SCAN_PAGE_DOWN:
2473 Status = FileBufferPageDown ();
2474 break;
2475
2476 //
2477 // delete
2478 //
2479 case SCAN_DELETE:
2480 if (!FileBuffer.ReadOnly) {
2481 Status = FileBufferDoDelete ();
2482 } else {
2483 Status = StatusBarSetStatusString (L"Read Only File Can Not Be Modified");
2484 }
2485
2486 break;
2487
2488 //
2489 // home
2490 //
2491 case SCAN_HOME:
2492 FileBufferMovePosition (FileBuffer.FilePosition.Row, 1);
2493 Status = EFI_SUCCESS;
2494 break;
2495
2496 //
2497 // end
2498 //
2499 case SCAN_END:
2500 Status = FileBufferEnd ();
2501 break;
2502
2503 //
2504 // insert
2505 //
2506 case SCAN_INSERT:
2507 FileBuffer.ModeInsert = (BOOLEAN)!FileBuffer.ModeInsert;
2508 Status = EFI_SUCCESS;
2509 break;
2510
2511 default:
2512 Status = StatusBarSetStatusString (L"Unknown Command");
2513 break;
2514 }
2515
2516 return Status;
2517 }
2518
2519 /**
2520 Check user specified FileRow is above current screen.
2521
2522 @param[in] FileRow The row of file position ( start from 1 ).
2523
2524 @retval TRUE It is above the current screen.
2525 @retval FALSE It is not above the current screen.
2526 **/
2527 BOOLEAN
2528 AboveCurrentScreen (
2529 IN UINTN FileRow
2530 )
2531 {
2532 //
2533 // if is to the above of the screen
2534 //
2535 if (FileRow < FileBuffer.LowVisibleRange.Row) {
2536 return TRUE;
2537 }
2538
2539 return FALSE;
2540 }
2541
2542 /**
2543 Check user specified FileRow is under current screen.
2544
2545 @param[in] FileRow The row of file position ( start from 1 ).
2546
2547 @retval TRUE It is under the current screen.
2548 @retval FALSE It is not under the current screen.
2549 **/
2550 BOOLEAN
2551 UnderCurrentScreen (
2552 IN UINTN FileRow
2553 )
2554 {
2555 //
2556 // if is to the under of the screen
2557 //
2558 if (FileRow > FileBuffer.LowVisibleRange.Row + (MainEditor.ScreenSize.Row - 2) - 1) {
2559 return TRUE;
2560 }
2561
2562 return FALSE;
2563 }
2564
2565 /**
2566 Check user specified FileCol is left to current screen.
2567
2568 @param[in] FileCol The column of file position ( start from 1 ).
2569
2570 @retval TRUE It is to the left.
2571 @retval FALSE It is not to the left.
2572 **/
2573 BOOLEAN
2574 LeftCurrentScreen (
2575 IN UINTN FileCol
2576 )
2577 {
2578 //
2579 // if is to the left of the screen
2580 //
2581 if (FileCol < FileBuffer.LowVisibleRange.Column) {
2582 return TRUE;
2583 }
2584
2585 return FALSE;
2586 }
2587
2588 /**
2589 Check user specified FileCol is right to current screen.
2590
2591 @param[in] FileCol The column of file position ( start from 1 ).
2592
2593 @retval TRUE It is to the right.
2594 @retval FALSE It is not to the right.
2595 **/
2596 BOOLEAN
2597 RightCurrentScreen (
2598 IN UINTN FileCol
2599 )
2600 {
2601 //
2602 // if is to the right of the screen
2603 //
2604 if (FileCol > FileBuffer.LowVisibleRange.Column + MainEditor.ScreenSize.Column - 1) {
2605 return TRUE;
2606 }
2607
2608 return FALSE;
2609 }
2610
2611 /**
2612 Advance/Retreat lines and set CurrentLine in FileBuffer to it
2613
2614 @param[in] Count The line number to advance/retreat
2615 >0 : advance
2616 <0: retreat
2617
2618 @retval NULL An error occured.
2619 @return The line after advance/retreat.
2620 **/
2621 EFI_EDITOR_LINE *
2622 MoveCurrentLine (
2623 IN INTN Count
2624 )
2625 {
2626 EFI_EDITOR_LINE *Line;
2627 UINTN AbsCount;
2628
2629 if (Count <= 0) {
2630 AbsCount = (UINTN)ABS(Count);
2631 Line = InternalEditorMiscLineRetreat (AbsCount,MainEditor.FileBuffer->CurrentLine,MainEditor.FileBuffer->ListHead);
2632 } else {
2633 Line = InternalEditorMiscLineAdvance ((UINTN)Count,MainEditor.FileBuffer->CurrentLine,MainEditor.FileBuffer->ListHead);
2634 }
2635
2636 if (Line == NULL) {
2637 return NULL;
2638 }
2639
2640 MainEditor.FileBuffer->CurrentLine = Line;
2641
2642 return Line;
2643 }
2644
2645 /**
2646 According to cursor's file position, adjust screen display
2647
2648 @param[in] NewFilePosRow The row of file position ( start from 1 ).
2649 @param[in] NewFilePosCol The column of file position ( start from 1 ).
2650 **/
2651 VOID
2652 FileBufferMovePosition (
2653 IN CONST UINTN NewFilePosRow,
2654 IN CONST UINTN NewFilePosCol
2655 )
2656 {
2657 INTN RowGap;
2658 INTN ColGap;
2659 UINTN Abs;
2660 BOOLEAN Above;
2661 BOOLEAN Under;
2662 BOOLEAN Right;
2663 BOOLEAN Left;
2664
2665 //
2666 // CALCULATE gap between current file position and new file position
2667 //
2668 RowGap = NewFilePosRow - FileBuffer.FilePosition.Row;
2669 ColGap = NewFilePosCol - FileBuffer.FilePosition.Column;
2670
2671 Under = UnderCurrentScreen (NewFilePosRow);
2672 Above = AboveCurrentScreen (NewFilePosRow);
2673 //
2674 // if is below current screen
2675 //
2676 if (Under) {
2677 //
2678 // display row will be unchanged
2679 //
2680 FileBuffer.FilePosition.Row = NewFilePosRow;
2681 } else {
2682 if (Above) {
2683 //
2684 // has enough above line, so display row unchanged
2685 // not has enough above lines, so the first line is at the
2686 // first display line
2687 //
2688 if (NewFilePosRow < (FileBuffer.DisplayPosition.Row - 1)) {
2689 FileBuffer.DisplayPosition.Row = NewFilePosRow + 1;
2690 }
2691
2692 FileBuffer.FilePosition.Row = NewFilePosRow;
2693 } else {
2694 //
2695 // in current screen
2696 //
2697 FileBuffer.FilePosition.Row = NewFilePosRow;
2698 if (RowGap < 0) {
2699 Abs = (UINTN)ABS(RowGap);
2700 FileBuffer.DisplayPosition.Row -= Abs;
2701 } else {
2702 FileBuffer.DisplayPosition.Row += RowGap;
2703 }
2704 }
2705 }
2706
2707 FileBuffer.LowVisibleRange.Row = FileBuffer.FilePosition.Row - (FileBuffer.DisplayPosition.Row - 2);
2708
2709 Right = RightCurrentScreen (NewFilePosCol);
2710 Left = LeftCurrentScreen (NewFilePosCol);
2711
2712 //
2713 // if right to current screen
2714 //
2715 if (Right) {
2716 //
2717 // display column will be changed to end
2718 //
2719 FileBuffer.DisplayPosition.Column = MainEditor.ScreenSize.Column;
2720 FileBuffer.FilePosition.Column = NewFilePosCol;
2721 } else {
2722 if (Left) {
2723 //
2724 // has enough left characters , so display row unchanged
2725 // not has enough left characters,
2726 // so the first character is at the first display column
2727 //
2728 if (NewFilePosCol < (FileBuffer.DisplayPosition.Column)) {
2729 FileBuffer.DisplayPosition.Column = NewFilePosCol;
2730 }
2731
2732 FileBuffer.FilePosition.Column = NewFilePosCol;
2733 } else {
2734 //
2735 // in current screen
2736 //
2737 FileBuffer.FilePosition.Column = NewFilePosCol;
2738 if (ColGap < 0) {
2739 Abs = (UINTN)(-ColGap);
2740 FileBuffer.DisplayPosition.Column -= Abs;
2741 } else {
2742 FileBuffer.DisplayPosition.Column += ColGap;
2743 }
2744 }
2745 }
2746
2747 FileBuffer.LowVisibleRange.Column = FileBuffer.FilePosition.Column - (FileBuffer.DisplayPosition.Column - 1);
2748
2749 //
2750 // let CurrentLine point to correct line;
2751 //
2752 FileBuffer.CurrentLine = MoveCurrentLine (RowGap);
2753
2754 }
2755
2756 /**
2757 Cut current line out and return a pointer to it.
2758
2759 @param[out] CutLine Upon a successful return pointer to the pointer to
2760 the allocated cut line.
2761
2762 @retval EFI_SUCCESS The cut was successful.
2763 @retval EFI_NOT_FOUND There was no selection to cut.
2764 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
2765 **/
2766 EFI_STATUS
2767 FileBufferCutLine (
2768 OUT EFI_EDITOR_LINE **CutLine
2769 )
2770 {
2771 EFI_EDITOR_LINE *Line;
2772 EFI_EDITOR_LINE *NewLine;
2773 UINTN Row;
2774 UINTN Col;
2775
2776 if (FileBuffer.ReadOnly) {
2777 StatusBarSetStatusString (L"Read Only File Can Not Be Modified");
2778 return EFI_SUCCESS;
2779 }
2780
2781 Line = FileBuffer.CurrentLine;
2782
2783 //
2784 // if is the last dummy line, SO CAN not cut
2785 //
2786 if (StrCmp (Line->Buffer, L"\0") == 0 && Line->Link.ForwardLink == FileBuffer.ListHead
2787 //
2788 // last line
2789 //
2790 ) {
2791 //
2792 // LAST LINE AND NOTHING ON THIS LINE, SO CUT NOTHING
2793 //
2794 StatusBarSetStatusString (L"Nothing to Cut");
2795 return EFI_NOT_FOUND;
2796 }
2797 //
2798 // if is the last line, so create a dummy line
2799 //
2800 if (Line->Link.ForwardLink == FileBuffer.ListHead) {
2801 //
2802 // last line
2803 // create a new line
2804 //
2805 NewLine = FileBufferCreateLine ();
2806 if (NewLine == NULL) {
2807 return EFI_OUT_OF_RESOURCES;
2808 }
2809 }
2810
2811 FileBuffer.NumLines--;
2812 Row = FileBuffer.FilePosition.Row;
2813 Col = 1;
2814 //
2815 // move home
2816 //
2817 FileBuffer.CurrentLine = CR (
2818 FileBuffer.CurrentLine->Link.ForwardLink,
2819 EFI_EDITOR_LINE,
2820 Link,
2821 LINE_LIST_SIGNATURE
2822 );
2823
2824 RemoveEntryList (&Line->Link);
2825
2826 FileBuffer.Lines = CR (FileBuffer.ListHead->ForwardLink, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE);
2827
2828 FileBufferMovePosition (Row, Col);
2829
2830 FileBuffer.FileModified = TRUE;
2831 FileBufferNeedRefresh = TRUE;
2832 FileBufferOnlyLineNeedRefresh = FALSE;
2833
2834 *CutLine = Line;
2835
2836 return EFI_SUCCESS;
2837 }
2838
2839 /**
2840 Paste a line into line list.
2841
2842 @retval EFI_SUCCESS The paste was successful.
2843 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
2844 **/
2845 EFI_STATUS
2846 FileBufferPasteLine (
2847 VOID
2848 )
2849 {
2850 EFI_EDITOR_LINE *Line;
2851 EFI_EDITOR_LINE *NewLine;
2852 UINTN Row;
2853 UINTN Col;
2854
2855 //
2856 // if nothing is on clip board
2857 // then do nothing
2858 //
2859 if (MainEditor.CutLine == NULL) {
2860 return EFI_SUCCESS;
2861 }
2862 //
2863 // read only file can not be pasted on
2864 //
2865 if (FileBuffer.ReadOnly) {
2866 StatusBarSetStatusString (L"Read Only File Can Not Be Modified");
2867 return EFI_SUCCESS;
2868 }
2869
2870 NewLine = LineDup (MainEditor.CutLine);
2871 if (NewLine == NULL) {
2872 return EFI_OUT_OF_RESOURCES;
2873 }
2874 //
2875 // insert it above current line
2876 //
2877 Line = FileBuffer.CurrentLine;
2878 NewLine->Link.BackLink = Line->Link.BackLink;
2879 NewLine->Link.ForwardLink = &Line->Link;
2880
2881 Line->Link.BackLink->ForwardLink = &NewLine->Link;
2882 Line->Link.BackLink = &NewLine->Link;
2883
2884 FileBuffer.NumLines++;
2885 FileBuffer.CurrentLine = NewLine;
2886
2887 FileBuffer.Lines = CR (FileBuffer.ListHead->ForwardLink, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE);
2888
2889 Col = 1;
2890 //
2891 // move home
2892 //
2893 Row = FileBuffer.FilePosition.Row;
2894
2895 FileBufferMovePosition (Row, Col);
2896
2897 //
2898 // after paste, set some value so that refresh knows to do something
2899 //
2900 FileBuffer.FileModified = TRUE;
2901 FileBufferNeedRefresh = TRUE;
2902 FileBufferOnlyLineNeedRefresh = FALSE;
2903
2904 return EFI_SUCCESS;
2905 }
2906
2907 /**
2908 Search string from current position on in file
2909
2910 @param[in] Str The search string.
2911 @param[in] Offset The offset from current position.
2912
2913 @retval EFI_SUCCESS The operation was successful.
2914 @retval EFI_NOT_FOUND The string Str was not found.
2915 **/
2916 EFI_STATUS
2917 FileBufferSearch (
2918 IN CONST CHAR16 *Str,
2919 IN CONST UINTN Offset
2920 )
2921 {
2922 CHAR16 *Current;
2923 UINTN Position;
2924 UINTN Row;
2925 UINTN Column;
2926 EFI_EDITOR_LINE *Line;
2927 CHAR16 *CharPos;
2928 LIST_ENTRY *Link;
2929 BOOLEAN Found;
2930
2931 Column = 0;
2932 Position = 0;
2933
2934 //
2935 // search if in current line
2936 //
2937 Current = FileBuffer.CurrentLine->Buffer + FileBuffer.FilePosition.Column - 1 + Offset;
2938
2939 if (Current >= (FileBuffer.CurrentLine->Buffer + FileBuffer.CurrentLine->Size)) {
2940 //
2941 // the end
2942 //
2943 Current = FileBuffer.CurrentLine->Buffer + FileBuffer.CurrentLine->Size;
2944 }
2945
2946 Found = FALSE;
2947
2948 CharPos = StrStr (Current, Str);
2949 if (CharPos != NULL) {
2950 Position = CharPos - Current + 1;
2951 Found = TRUE;
2952 }
2953
2954 //
2955 // found
2956 //
2957 if (Found) {
2958 Column = (Position - 1) + FileBuffer.FilePosition.Column + Offset;
2959 Row = FileBuffer.FilePosition.Row;
2960 } else {
2961 //
2962 // not found so find through next lines
2963 //
2964 Link = FileBuffer.CurrentLine->Link.ForwardLink;
2965
2966 Row = FileBuffer.FilePosition.Row + 1;
2967 while (Link != FileBuffer.ListHead) {
2968 Line = CR (Link, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE);
2969 // Position = StrStr (Line->Buffer, Str);
2970 CharPos = StrStr (Line->Buffer, Str);
2971 if (CharPos != NULL) {
2972 Position = CharPos - Line->Buffer + 1;
2973 Found = TRUE;
2974 }
2975
2976 if (Found) {
2977 //
2978 // found
2979 //
2980 Column = Position;
2981 break;
2982 }
2983
2984 Row++;
2985 Link = Link->ForwardLink;
2986 }
2987
2988 if (Link == FileBuffer.ListHead) {
2989 Found = FALSE;
2990 } else {
2991 Found = TRUE;
2992 }
2993 }
2994
2995 if (!Found) {
2996 return EFI_NOT_FOUND;
2997 }
2998
2999 FileBufferMovePosition (Row, Column);
3000
3001 //
3002 // call refresh to fresh edit area,
3003 // because the outer may loop to find multiply occurrence of this string
3004 //
3005 FileBufferRefresh ();
3006
3007 return EFI_SUCCESS;
3008 }
3009
3010 /**
3011 Replace SearchLen characters from current position on with Replace.
3012
3013 This will modify the current buffer at the current position.
3014
3015 @param[in] Replace The string to replace.
3016 @param[in] SearchLen Search string's length.
3017
3018 @retval EFI_SUCCESS The operation was successful.
3019 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
3020 **/
3021 EFI_STATUS
3022 FileBufferReplace (
3023 IN CONST CHAR16 *Replace,
3024 IN CONST UINTN SearchLen
3025 )
3026 {
3027 UINTN ReplaceLen;
3028 UINTN Index;
3029 CHAR16 *Buffer;
3030 UINTN NewSize;
3031 UINTN OldSize;
3032 UINTN Gap;
3033
3034 ReplaceLen = StrLen (Replace);
3035
3036 OldSize = FileBuffer.CurrentLine->Size + 1;
3037 //
3038 // include CHAR_NULL
3039 //
3040 NewSize = OldSize + (ReplaceLen - SearchLen);
3041
3042 if (ReplaceLen > SearchLen) {
3043 //
3044 // do not have the enough space
3045 //
3046 if (FileBuffer.CurrentLine->TotalSize + 1 <= NewSize) {
3047 FileBuffer.CurrentLine->Buffer = ReallocatePool (
3048 2 * OldSize,
3049 2 * NewSize,
3050 FileBuffer.CurrentLine->Buffer
3051 );
3052 FileBuffer.CurrentLine->TotalSize = NewSize - 1;
3053 }
3054
3055 if (FileBuffer.CurrentLine->Buffer == NULL) {
3056 return EFI_OUT_OF_RESOURCES;
3057 }
3058 //
3059 // the end CHAR_NULL character;
3060 //
3061 Buffer = FileBuffer.CurrentLine->Buffer + (NewSize - 1);
3062 Gap = ReplaceLen - SearchLen;
3063
3064 //
3065 // keep the latter part
3066 //
3067 for (Index = 0; Index < (FileBuffer.CurrentLine->Size - FileBuffer.FilePosition.Column - SearchLen + 2); Index++) {
3068 *Buffer = *(Buffer - Gap);
3069 Buffer--;
3070 }
3071 //
3072 // set replace into it
3073 //
3074 Buffer = FileBuffer.CurrentLine->Buffer + FileBuffer.FilePosition.Column - 1;
3075 for (Index = 0; Index < ReplaceLen; Index++) {
3076 Buffer[Index] = Replace[Index];
3077 }
3078 }
3079
3080 if (ReplaceLen < SearchLen) {
3081 Buffer = FileBuffer.CurrentLine->Buffer + FileBuffer.FilePosition.Column - 1;
3082
3083 for (Index = 0; Index < ReplaceLen; Index++) {
3084 Buffer[Index] = Replace[Index];
3085 }
3086
3087 Buffer += ReplaceLen;
3088 Gap = SearchLen - ReplaceLen;
3089
3090 //
3091 // set replace into it
3092 //
3093 for (Index = 0; Index < (FileBuffer.CurrentLine->Size - FileBuffer.FilePosition.Column - ReplaceLen + 2); Index++) {
3094 *Buffer = *(Buffer + Gap);
3095 Buffer++;
3096 }
3097 }
3098
3099 if (ReplaceLen == SearchLen) {
3100 Buffer = FileBuffer.CurrentLine->Buffer + FileBuffer.FilePosition.Column - 1;
3101 for (Index = 0; Index < ReplaceLen; Index++) {
3102 Buffer[Index] = Replace[Index];
3103 }
3104 }
3105
3106 FileBuffer.CurrentLine->Size += (ReplaceLen - SearchLen);
3107
3108 FileBufferOnlyLineNeedRefresh = TRUE;
3109
3110 FileBuffer.FileModified = TRUE;
3111
3112 MainTitleBarRefresh (MainEditor.FileBuffer->FileName, MainEditor.FileBuffer->FileType, MainEditor.FileBuffer->ReadOnly, MainEditor.FileBuffer->FileModified, MainEditor.ScreenSize.Column, MainEditor.ScreenSize.Row, 0, 0);
3113 FileBufferRestorePosition ();
3114 FileBufferRefresh ();
3115
3116 return EFI_SUCCESS;
3117 }
3118
3119 /**
3120 Move the mouse cursor position.
3121
3122 @param[in] TextX The new x-coordinate.
3123 @param[in] TextY The new y-coordinate.
3124 **/
3125 VOID
3126 FileBufferAdjustMousePosition (
3127 IN CONST INT32 TextX,
3128 IN CONST INT32 TextY
3129 )
3130 {
3131 UINTN CoordinateX;
3132 UINTN CoordinateY;
3133 UINTN AbsX;
3134 UINTN AbsY;
3135
3136 //
3137 // TextX and TextY is mouse movement data returned by mouse driver
3138 // This function will change it to MousePosition
3139 //
3140 //
3141 // get absolute value
3142 //
3143
3144 AbsX = ABS(TextX);
3145 AbsY = ABS(TextY);
3146
3147 CoordinateX = FileBuffer.MousePosition.Column;
3148 CoordinateY = FileBuffer.MousePosition.Row;
3149
3150 if (TextX >= 0) {
3151 CoordinateX += TextX;
3152 } else {
3153 if (CoordinateX >= AbsX) {
3154 CoordinateX -= AbsX;
3155 } else {
3156 CoordinateX = 0;
3157 }
3158 }
3159
3160 if (TextY >= 0) {
3161 CoordinateY += TextY;
3162 } else {
3163 if (CoordinateY >= AbsY) {
3164 CoordinateY -= AbsY;
3165 } else {
3166 CoordinateY = 0;
3167 }
3168 }
3169 //
3170 // check whether new mouse column position is beyond screen
3171 // if not, adjust it
3172 //
3173 if (CoordinateX >= 1 && CoordinateX <= MainEditor.ScreenSize.Column) {
3174 FileBuffer.MousePosition.Column = CoordinateX;
3175 } else if (CoordinateX < 1) {
3176 FileBuffer.MousePosition.Column = 1;
3177 } else if (CoordinateX > MainEditor.ScreenSize.Column) {
3178 FileBuffer.MousePosition.Column = MainEditor.ScreenSize.Column;
3179 }
3180 //
3181 // check whether new mouse row position is beyond screen
3182 // if not, adjust it
3183 //
3184 if (CoordinateY >= 2 && CoordinateY <= (MainEditor.ScreenSize.Row - 1)) {
3185 FileBuffer.MousePosition.Row = CoordinateY;
3186 } else if (CoordinateY < 2) {
3187 FileBuffer.MousePosition.Row = 2;
3188 } else if (CoordinateY > (MainEditor.ScreenSize.Row - 1)) {
3189 FileBuffer.MousePosition.Row = (MainEditor.ScreenSize.Row - 1);
3190 }
3191
3192 }
3193
3194 /**
3195 Search and replace operation.
3196
3197 @param[in] SearchStr The string to search for.
3198 @param[in] ReplaceStr The string to replace with.
3199 @param[in] Offset The column to start at.
3200 **/
3201 EFI_STATUS
3202 FileBufferReplaceAll (
3203 IN CHAR16 *SearchStr,
3204 IN CHAR16 *ReplaceStr,
3205 IN UINTN Offset
3206 )
3207 {
3208 CHAR16 *Buffer;
3209 UINTN Position;
3210 UINTN Column;
3211 UINTN ReplaceLen;
3212 UINTN SearchLen;
3213 UINTN Index;
3214 UINTN NewSize;
3215 UINTN OldSize;
3216 UINTN Gap;
3217 EFI_EDITOR_LINE *Line;
3218 LIST_ENTRY *Link;
3219 CHAR16 *CharPos;
3220
3221 SearchLen = StrLen (SearchStr);
3222 ReplaceLen = StrLen (ReplaceStr);
3223
3224 Column = FileBuffer.FilePosition.Column + Offset - 1;
3225
3226 if (Column > FileBuffer.CurrentLine->Size) {
3227 Column = FileBuffer.CurrentLine->Size;
3228 }
3229
3230 Link = &(FileBuffer.CurrentLine->Link);
3231
3232 while (Link != FileBuffer.ListHead) {
3233 Line = CR (Link, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE);
3234 CharPos = StrStr (Line->Buffer + Column, SearchStr);
3235 if (CharPos != NULL) {
3236 Position = CharPos - Line->Buffer;// + Column;
3237 //
3238 // found
3239 //
3240 if (ReplaceLen > SearchLen) {
3241 OldSize = Line->Size + 1;
3242 //
3243 // include CHAR_NULL
3244 //
3245 NewSize = OldSize + (ReplaceLen - SearchLen);
3246
3247 //
3248 // do not have the enough space
3249 //
3250 if (Line->TotalSize + 1 <= NewSize) {
3251 Line->Buffer = ReallocatePool (
3252 2 * OldSize,
3253 2 * NewSize,
3254 Line->Buffer
3255 );
3256 Line->TotalSize = NewSize - 1;
3257 }
3258
3259 if (Line->Buffer == NULL) {
3260 return EFI_OUT_OF_RESOURCES;
3261 }
3262 //
3263 // the end CHAR_NULL character;
3264 //
3265 Buffer = Line->Buffer + (NewSize - 1);
3266 Gap = ReplaceLen - SearchLen;
3267
3268 //
3269 // keep the latter part
3270 //
3271 for (Index = 0; Index < (Line->Size - Position - SearchLen + 1); Index++) {
3272 *Buffer = *(Buffer - Gap);
3273 Buffer--;
3274 }
3275
3276 } else if (ReplaceLen < SearchLen){
3277 Buffer = Line->Buffer + Position + ReplaceLen;
3278 Gap = SearchLen - ReplaceLen;
3279
3280 for (Index = 0; Index < (Line->Size - Position - ReplaceLen + 1); Index++) {
3281 *Buffer = *(Buffer + Gap);
3282 Buffer++;
3283 }
3284 } else {
3285 ASSERT(ReplaceLen == SearchLen);
3286 }
3287 //
3288 // set replace into it
3289 //
3290 Buffer = Line->Buffer + Position;
3291 for (Index = 0; Index < ReplaceLen; Index++) {
3292 Buffer[Index] = ReplaceStr[Index];
3293 }
3294
3295 Line->Size += (ReplaceLen - SearchLen);
3296 Column += ReplaceLen;
3297 } else {
3298 //
3299 // not found
3300 //
3301 Column = 0;
3302 Link = Link->ForwardLink;
3303 }
3304 }
3305 //
3306 // call refresh to fresh edit area
3307 //
3308 FileBuffer.FileModified = TRUE;
3309 FileBufferNeedRefresh = TRUE;
3310 FileBufferRefresh ();
3311
3312 return EFI_SUCCESS;
3313 }
3314
3315 /**
3316 Set the modified state to TRUE.
3317 **/
3318 VOID
3319 FileBufferSetModified (
3320 VOID
3321 )
3322 {
3323 FileBuffer.FileModified = TRUE;
3324 }
3325