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