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