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