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