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