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