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