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