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