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