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