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