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