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