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