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