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