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