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