1 /** @file 2 Implements editor 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 "EditStatusBar.h" 17 #include "EditInputBar.h" 18 #include "EditMenuBar.h" 19 20 // 21 // the first time editor launch 22 // 23 BOOLEAN EditorFirst; 24 25 // 26 // it's time editor should exit 27 // 28 BOOLEAN EditorExit; 29 30 BOOLEAN EditorMouseAction; 31 32 extern EFI_EDITOR_FILE_BUFFER FileBuffer; 33 34 extern BOOLEAN FileBufferNeedRefresh; 35 36 extern BOOLEAN FileBufferOnlyLineNeedRefresh; 37 38 extern BOOLEAN FileBufferMouseNeedRefresh; 39 40 extern EFI_EDITOR_FILE_BUFFER FileBufferBackupVar; 41 42 EFI_EDITOR_GLOBAL_EDITOR MainEditor; 43 44 45 /** 46 Load a file from disk to editor 47 48 @retval EFI_SUCCESS The operation was successful. 49 @retval EFI_LOAD_ERROR A load error occured. 50 @retval EFI_OUT_OF_RESOURCES A memory allocation failed. 51 **/ 52 EFI_STATUS 53 MainCommandOpenFile ( 54 VOID 55 ); 56 57 /** 58 Switch a file from ASCII to UNICODE or vise-versa. 59 60 @retval EFI_SUCCESS The switch was ok or a warning was presented. 61 **/ 62 EFI_STATUS 63 MainCommandSwitchFileType ( 64 VOID 65 ); 66 67 /** 68 move cursor to specified lines 69 70 @retval EFI_SUCCESS The operation was successful. 71 **/ 72 EFI_STATUS 73 MainCommandGotoLine ( 74 VOID 75 ); 76 77 /** 78 Save current file to disk, you can save to current file name or 79 save to another file name. 80 81 @retval EFI_SUCCESS The file was saved correctly. 82 @retval EFI_OUT_OF_RESOURCES A memory allocation failed. 83 @retval EFI_LOAD_ERROR A file access error occured. 84 **/ 85 EFI_STATUS 86 MainCommandSaveFile ( 87 VOID 88 ); 89 90 /** 91 Show help information for the editor. 92 93 @retval EFI_SUCCESS The operation was successful. 94 **/ 95 EFI_STATUS 96 MainCommandDisplayHelp ( 97 VOID 98 ); 99 100 /** 101 exit editor 102 103 @retval EFI_SUCCESS The operation was successful. 104 @retval EFI_OUT_OF_RESOURCES A memory allocation failed. 105 @retval EFI_LOAD_ERROR A load error occured. 106 **/ 107 EFI_STATUS 108 MainCommandExit ( 109 VOID 110 ); 111 112 /** 113 search string in file buffer 114 115 @retval EFI_SUCCESS The operation was successful. 116 @retval EFI_OUT_OF_RESOURCES A memory allocation failed. 117 @retval EFI_LOAD_ERROR A load error occured. 118 **/ 119 EFI_STATUS 120 MainCommandSearch ( 121 VOID 122 ); 123 124 /** 125 search string in file buffer, and replace it with another str 126 127 @retval EFI_SUCCESS The operation was successful. 128 @retval EFI_OUT_OF_RESOURCES A memory allocation failed. 129 @retval EFI_LOAD_ERROR A load error occured. 130 **/ 131 EFI_STATUS 132 MainCommandSearchReplace ( 133 VOID 134 ); 135 136 /** 137 cut current line to clipboard 138 139 @retval EFI_SUCCESS The operation was successful. 140 @retval EFI_OUT_OF_RESOURCES A memory allocation failed. 141 @retval EFI_LOAD_ERROR A load error occured. 142 **/ 143 EFI_STATUS 144 MainCommandCutLine ( 145 VOID 146 ); 147 148 /** 149 paste line to file buffer. 150 151 @retval EFI_SUCCESS The operation was successful. 152 @retval EFI_OUT_OF_RESOURCES A memory allocation failed. 153 @retval EFI_LOAD_ERROR A load error occured. 154 **/ 155 EFI_STATUS 156 MainCommandPasteLine ( 157 VOID 158 ); 159 160 /** 161 Help info that will be displayed. 162 **/ 163 EFI_STRING_ID MainMenuHelpInfo[] = { 164 STRING_TOKEN(STR_EDIT_HELP_TITLE), 165 STRING_TOKEN(STR_EDIT_HELP_BLANK), 166 STRING_TOKEN(STR_EDIT_HELP_LIST_TITLE), 167 STRING_TOKEN(STR_EDIT_HELP_DIV), 168 STRING_TOKEN(STR_EDIT_HELP_GO_TO_LINE), 169 STRING_TOKEN(STR_EDIT_HELP_SAVE_FILE), 170 STRING_TOKEN(STR_EDIT_HELP_EXIT), 171 STRING_TOKEN(STR_EDIT_HELP_SEARCH), 172 STRING_TOKEN(STR_EDIT_HELP_SEARCH_REPLACE), 173 STRING_TOKEN(STR_EDIT_HELP_CUT_LINE), 174 STRING_TOKEN(STR_EDIT_HELP_PASTE_LINE), 175 STRING_TOKEN(STR_EDIT_HELP_OPEN_FILE), 176 STRING_TOKEN(STR_EDIT_HELP_FILE_TYPE), 177 STRING_TOKEN(STR_EDIT_HELP_BLANK), 178 STRING_TOKEN(STR_EDIT_HELP_EXIT_HELP), 179 STRING_TOKEN(STR_EDIT_HELP_BLANK), 180 STRING_TOKEN(STR_EDIT_HELP_BLANK), 181 STRING_TOKEN(STR_EDIT_HELP_BLANK), 182 STRING_TOKEN(STR_EDIT_HELP_BLANK), 183 STRING_TOKEN(STR_EDIT_HELP_BLANK), 184 STRING_TOKEN(STR_EDIT_HELP_BLANK), 185 STRING_TOKEN(STR_EDIT_HELP_BLANK), 186 STRING_TOKEN(STR_EDIT_HELP_DIV), 187 0 188 }; 189 190 MENU_ITEM_FUNCTION MainControlBasedMenuFunctions[] = { 191 NULL, 192 NULL, /* Ctrl - A */ 193 NULL, /* Ctrl - B */ 194 NULL, /* Ctrl - C */ 195 NULL, /* Ctrl - D */ 196 MainCommandDisplayHelp, /* Ctrl - E */ 197 MainCommandSearch, /* Ctrl - F */ 198 MainCommandGotoLine, /* Ctrl - G */ 199 NULL, /* Ctrl - H */ 200 NULL, /* Ctrl - I */ 201 NULL, /* Ctrl - J */ 202 MainCommandCutLine, /* Ctrl - K */ 203 NULL, /* Ctrl - L */ 204 NULL, /* Ctrl - M */ 205 NULL, /* Ctrl - N */ 206 MainCommandOpenFile, /* Ctrl - O */ 207 NULL, /* Ctrl - P */ 208 MainCommandExit, /* Ctrl - Q */ 209 MainCommandSearchReplace, /* Ctrl - R */ 210 MainCommandSaveFile, /* Ctrl - S */ 211 MainCommandSwitchFileType, /* Ctrl - T */ 212 MainCommandPasteLine, /* Ctrl - U */ 213 NULL, /* Ctrl - V */ 214 NULL, /* Ctrl - W */ 215 NULL, /* Ctrl - X */ 216 NULL, /* Ctrl - Y */ 217 NULL, /* Ctrl - Z */ 218 }; 219 220 EDITOR_MENU_ITEM MainMenuItems[] = { 221 { 222 STRING_TOKEN(STR_EDIT_LIBMENUBAR_GO_TO_LINE), 223 STRING_TOKEN(STR_EDIT_LIBMENUBAR_F1), 224 MainCommandGotoLine 225 }, 226 { 227 STRING_TOKEN(STR_EDIT_LIBMENUBAR_SAVE_FILE), 228 STRING_TOKEN(STR_EDIT_LIBMENUBAR_F2), 229 MainCommandSaveFile 230 }, 231 { 232 STRING_TOKEN(STR_EDIT_LIBMENUBAR_EXIT), 233 STRING_TOKEN(STR_EDIT_LIBMENUBAR_F3), 234 MainCommandExit 235 }, 236 237 { 238 STRING_TOKEN(STR_EDIT_LIBMENUBAR_SEARCH), 239 STRING_TOKEN(STR_EDIT_LIBMENUBAR_F4), 240 MainCommandSearch 241 }, 242 { 243 STRING_TOKEN(STR_EDIT_LIBMENUBAR_SEARCH_REPLACE), 244 STRING_TOKEN(STR_EDIT_LIBMENUBAR_F5), 245 MainCommandSearchReplace 246 }, 247 { 248 STRING_TOKEN(STR_EDIT_LIBMENUBAR_CUT_LINE), 249 STRING_TOKEN(STR_EDIT_LIBMENUBAR_F6), 250 MainCommandCutLine 251 }, 252 { 253 STRING_TOKEN(STR_EDIT_LIBMENUBAR_PASTE_LINE), 254 STRING_TOKEN(STR_EDIT_LIBMENUBAR_F7), 255 MainCommandPasteLine 256 }, 257 258 { 259 STRING_TOKEN(STR_EDIT_LIBMENUBAR_OPEN_FILE), 260 STRING_TOKEN(STR_EDIT_LIBMENUBAR_F8), 261 MainCommandOpenFile 262 }, 263 { 264 STRING_TOKEN(STR_EDIT_LIBMENUBAR_FILE_TYPE), 265 STRING_TOKEN(STR_EDIT_LIBMENUBAR_F9), 266 MainCommandSwitchFileType 267 }, 268 { 269 STRING_TOKEN(STR_EDIT_LIBMENUBAR_FILE_TYPE), 270 STRING_TOKEN(STR_EDIT_LIBMENUBAR_F11), 271 MainCommandSwitchFileType 272 }, 273 274 { 275 0, 276 0, 277 NULL 278 } 279 }; 280 281 282 /** 283 Load a file from disk to editor 284 285 @retval EFI_SUCCESS The operation was successful. 286 @retval EFI_LOAD_ERROR A load error occured. 287 @retval EFI_OUT_OF_RESOURCES A memory allocation failed. 288 **/ 289 EFI_STATUS 290 MainCommandOpenFile ( 291 VOID 292 ) 293 { 294 BOOLEAN Done; 295 EFI_STATUS Status; 296 297 // 298 // This command will open a file from current working directory. 299 // Read-only file can also be opened. But it can not be modified. 300 // Below is the scenario of Open File command: 301 // 1.IF currently opened file has not been modIFied, directly go to step . 302 // IF currently opened file has been modified, 303 // an Input Bar will be prompted as : 304 // "File Modified. Save ( Yes/No/Cancel) ?" 305 // IF user press 'y' or 'Y', currently opened file will be saved. 306 // IF user press 'n' or 'N', currently opened file will 307 // not be saved. 308 // IF user press 'c' or 'C' or ESC, Open File command ends and 309 // currently opened file is still opened. 310 // 311 // 2. An Input Bar will be prompted as : "File Name to Open: " 312 // IF user press ESC, Open File command ends and 313 // currently opened file is still opened. 314 // Any other inputs with a Return will 315 // cause currently opened file close. 316 // 317 // 3. IF user input file name is an existing file , this file will be read 318 // and opened. 319 // IF user input file name is a new file, this file will be created 320 // and opened. This file's type ( UNICODE or ASCII ) is the same 321 // with the old file. 322 // if current file is modified, so you need to choose 323 // whether to save it first. 324 // 325 if (MainEditor.FileBuffer->FileModified) { 326 327 Status = InputBarSetPrompt (L"File modified. Save (Yes/No/Cancel) ? "); 328 if (EFI_ERROR (Status)) { 329 return Status; 330 } 331 // 332 // the answer is just one character 333 // 334 Status = InputBarSetStringSize (1); 335 if (EFI_ERROR (Status)) { 336 return Status; 337 } 338 // 339 // loop for user's answer 340 // valid answer is just 'y' 'Y', 'n' 'N', 'c' 'C' 341 // 342 Done = FALSE; 343 while (!Done) { 344 Status = InputBarRefresh (MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column); 345 StatusBarSetRefresh(); 346 347 // 348 // ESC pressed 349 // 350 if (Status == EFI_NOT_READY) { 351 return EFI_SUCCESS; 352 } 353 354 switch (InputBarGetString()[0]) { 355 case L'y': 356 case L'Y': 357 // 358 // want to save this file first 359 // 360 Status = FileBufferSave (MainEditor.FileBuffer->FileName); 361 if (EFI_ERROR (Status)) { 362 return Status; 363 } 364 365 MainTitleBarRefresh (MainEditor.FileBuffer->FileName, MainEditor.FileBuffer->FileType, MainEditor.FileBuffer->ReadOnly, MainEditor.FileBuffer->FileModified, MainEditor.ScreenSize.Column, MainEditor.ScreenSize.Row, 0, 0); 366 FileBufferRestorePosition (); 367 Done = TRUE; 368 break; 369 370 case L'n': 371 case L'N': 372 // 373 // the file won't be saved 374 // 375 Done = TRUE; 376 break; 377 378 case L'c': 379 case L'C': 380 return EFI_SUCCESS; 381 } 382 } 383 } 384 // 385 // TO get the open file name 386 // 387 Status = InputBarSetPrompt (L"File Name to Open: "); 388 if (EFI_ERROR (Status)) { 389 FileBufferRead (MainEditor.FileBuffer->FileName, TRUE); 390 return Status; 391 } 392 393 Status = InputBarSetStringSize (100); 394 if (EFI_ERROR (Status)) { 395 FileBufferRead (MainEditor.FileBuffer->FileName, TRUE); 396 return Status; 397 } 398 399 while (1) { 400 Status = InputBarRefresh (MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column); 401 StatusBarSetRefresh(); 402 403 // 404 // ESC pressed 405 // 406 if (Status == EFI_NOT_READY) { 407 return EFI_SUCCESS; 408 } 409 // 410 // The input string length should > 0 411 // 412 if (StrLen (InputBarGetString()) > 0) { 413 // 414 // CHECK if filename is valid 415 // 416 if (!IsValidFileName (InputBarGetString())) { 417 FileBufferRead (MainEditor.FileBuffer->FileName, TRUE); 418 StatusBarSetStatusString (L"Invalid File Name"); 419 return EFI_SUCCESS; 420 } 421 422 break; 423 } 424 } 425 // 426 // read from disk 427 // 428 Status = FileBufferRead (InputBarGetString(), FALSE); 429 430 if (EFI_ERROR (Status)) { 431 FileBufferRead (MainEditor.FileBuffer->FileName, TRUE); 432 return EFI_LOAD_ERROR; 433 } 434 435 return EFI_SUCCESS; 436 } 437 438 /** 439 Switch a file from ASCII to UNICODE or vise-versa. 440 441 @retval EFI_SUCCESS The switch was ok or a warning was presented. 442 **/ 443 EFI_STATUS 444 MainCommandSwitchFileType ( 445 VOID 446 ) 447 { 448 // 449 // Below is the scenario of File Type command: 450 // After File Type is executed, file type will be changed to another type 451 // if file is read-only, can not be modified 452 // 453 if (MainEditor.FileBuffer->ReadOnly) { 454 StatusBarSetStatusString (L"Read Only File Can Not Be Modified"); 455 return EFI_SUCCESS; 456 } 457 458 if (MainEditor.FileBuffer->FileType == FileTypeUnicode) { 459 MainEditor.FileBuffer->FileType = FileTypeAscii; 460 } else { 461 MainEditor.FileBuffer->FileType = FileTypeUnicode; 462 } 463 464 MainEditor.FileBuffer->FileModified = TRUE; 465 466 return EFI_SUCCESS; 467 } 468 469 /** 470 cut current line to clipboard 471 472 @retval EFI_SUCCESS The operation was successful. 473 @retval EFI_OUT_OF_RESOURCES A memory allocation failed. 474 @retval EFI_LOAD_ERROR A load error occured. 475 **/ 476 EFI_STATUS 477 MainCommandCutLine ( 478 VOID 479 ) 480 { 481 EFI_STATUS Status; 482 EFI_EDITOR_LINE *Line; 483 484 // 485 // This command will cut current line ( where cursor is on ) to clip board. 486 // And cursor will move to the beginning of next line. 487 // Below is the scenario of Cut Line command: 488 // 1. IF cursor is on valid line, current line will be cut to clip board. 489 // IF cursor is not on valid line, an Status String will be prompted : 490 // "Nothing to Cut". 491 // 492 Line = NULL; 493 Status = FileBufferCutLine (&Line); 494 if (Status == EFI_NOT_FOUND) { 495 return EFI_SUCCESS; 496 } 497 498 if (EFI_ERROR (Status)) { 499 return Status; 500 } 501 502 MainEditor.CutLine = Line; 503 504 return EFI_SUCCESS; 505 } 506 507 /** 508 paste line to file buffer. 509 510 @retval EFI_SUCCESS The operation was successful. 511 @retval EFI_OUT_OF_RESOURCES A memory allocation failed. 512 @retval EFI_LOAD_ERROR A load error occured. 513 **/ 514 EFI_STATUS 515 MainCommandPasteLine ( 516 VOID 517 ) 518 { 519 EFI_STATUS Status; 520 521 // 522 // Below is the scenario of Paste Line command: 523 // 1. IF nothing is on clipboard, a Status String will be prompted : 524 // "No Line to Paste" and Paste Line command ends. 525 // IF something is on clipboard, insert it above current line. 526 // nothing on clipboard 527 // 528 if (MainEditor.CutLine == NULL) { 529 StatusBarSetStatusString (L"No Line to Paste"); 530 return EFI_SUCCESS; 531 } 532 533 Status = FileBufferPasteLine (); 534 535 return Status; 536 } 537 538 539 /** 540 search string in file buffer 541 542 @retval EFI_SUCCESS The operation was successful. 543 @retval EFI_OUT_OF_RESOURCES A memory allocation failed. 544 @retval EFI_LOAD_ERROR A load error occured. 545 **/ 546 EFI_STATUS 547 MainCommandSearch ( 548 VOID 549 ) 550 { 551 EFI_STATUS Status; 552 CHAR16 *Buffer; 553 BOOLEAN Done; 554 UINTN Offset; 555 556 // 557 // Below is the scenario of Search command: 558 // 1. An Input Bar will be prompted : "Enter Search String:". 559 // IF user press ESC, Search command ends. 560 // IF user just press Enter, Search command ends. 561 // IF user inputs the search string, do Step 2. 562 // 563 // 2. IF input search string is found, cursor will move to the first 564 // occurrence and do Step 3. 565 // IF input search string is not found, a Status String 566 // "Search String Not Found" will be prompted and Search command ends. 567 // 568 // 3. An Input Bar will be prompted: "Find Next (Yes/No/Cancel ) ?". 569 // IF user press ESC, Search command ends. 570 // IF user press 'y' or 'Y', do Step 2. 571 // IF user press 'n' or 'N', Search command ends. 572 // IF user press 'c' or 'C', Search command ends. 573 // 574 Status = InputBarSetPrompt (L"Enter Search String: "); 575 if (EFI_ERROR (Status)) { 576 return Status; 577 } 578 579 Status = InputBarSetStringSize (40); 580 if (EFI_ERROR (Status)) { 581 return Status; 582 } 583 584 Status = InputBarRefresh (MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column); 585 StatusBarSetRefresh(); 586 587 // 588 // ESC 589 // 590 if (Status == EFI_NOT_READY) { 591 return EFI_SUCCESS; 592 } 593 // 594 // just enter pressed 595 // 596 if (StrLen (InputBarGetString()) == 0) { 597 return EFI_SUCCESS; 598 } 599 600 Buffer = CatSPrint (NULL, L"%s", InputBarGetString()); 601 if (Buffer == NULL) { 602 return EFI_OUT_OF_RESOURCES; 603 } 604 // 605 // the first time , search from current position 606 // 607 Offset = 0; 608 do { 609 // 610 // since search may be continued to search multiple times 611 // so we need to backup editor each time 612 // 613 MainEditorBackup (); 614 615 Status = FileBufferSearch (Buffer, Offset); 616 617 if (Status == EFI_NOT_FOUND) { 618 break; 619 } 620 // 621 // Find next 622 // 623 Status = InputBarSetPrompt (L"Find Next (Yes/No) ?"); 624 if (EFI_ERROR (Status)) { 625 FreePool (Buffer); 626 return Status; 627 } 628 629 Status = InputBarSetStringSize (1); 630 if (EFI_ERROR (Status)) { 631 FreePool (Buffer); 632 return Status; 633 } 634 635 Done = FALSE; 636 while (!Done) { 637 Status = InputBarRefresh (MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column); 638 StatusBarSetRefresh(); 639 640 // 641 // ESC pressed 642 // 643 if (Status == EFI_NOT_READY) { 644 FreePool (Buffer); 645 return EFI_SUCCESS; 646 } 647 648 switch (InputBarGetString()[0]) { 649 case L'y': 650 case L'Y': 651 Done = TRUE; 652 break; 653 654 case L'n': 655 case L'N': 656 FreePool (Buffer); 657 return EFI_SUCCESS; 658 659 } 660 // 661 // end of which 662 // 663 } 664 // 665 // end of while !Done 666 // for search second, third time, search from current position + strlen 667 // 668 Offset = StrLen (Buffer); 669 670 } while (1); 671 // 672 // end of do 673 // 674 FreePool (Buffer); 675 StatusBarSetStatusString (L"Search String Not Found"); 676 677 return EFI_SUCCESS; 678 } 679 680 /** 681 Search string in file buffer, and replace it with another str. 682 683 @retval EFI_SUCCESS The operation was successful. 684 @retval EFI_OUT_OF_RESOURCES A memory allocation failed. 685 @retval EFI_LOAD_ERROR A load error occured. 686 **/ 687 EFI_STATUS 688 MainCommandSearchReplace ( 689 VOID 690 ) 691 { 692 EFI_STATUS Status; 693 CHAR16 *Search; 694 CHAR16 *Replace; 695 BOOLEAN Done; 696 BOOLEAN First; 697 BOOLEAN ReplaceOption; 698 UINTN SearchLen; 699 UINTN ReplaceLen; 700 BOOLEAN ReplaceAll; 701 702 ReplaceOption = FALSE; 703 704 // 705 // Below is the scenario of Search/Replace command: 706 // 1. An Input Bar is prompted : "Enter Search String:". 707 // IF user press ESC, Search/Replace command ends. 708 // IF user just press Enter, Search/Replace command ends. 709 // IF user inputs the search string S, do Step 2. 710 // 711 // 2. An Input Bar is prompted: "Replace With:". 712 // IF user press ESC, Search/Replace command ends. 713 // IF user inputs the replace string R, do Step 3. 714 // 715 // 3. IF input search string is not found, an Status String 716 // "Search String Not Found" will be prompted 717 // and Search/Replace command ends 718 // IF input search string is found, do Step 4. 719 // 720 // 4. An Input Bar will be prompted: "Replace ( Yes/No/All/Cancel )?" 721 // IF user press 'y' or 'Y', S will be replaced with R and do Step 5 722 // IF user press 'n' or 'N', S will not be replaced and do Step 5. 723 // IF user press 'a' or 'A', all the S from file current position on 724 // will be replaced with R and Search/Replace command ends. 725 // IF user press 'c' or 'C' or ESC, Search/Replace command ends. 726 // 727 // 5. An Input Bar will be prompted: "Find Next (Yes/No/Cancel) ?". 728 // IF user press ESC, Search/Replace command ends. 729 // IF user press 'y' or 'Y', do Step 3. 730 // IF user press 'n' or 'N', Search/Replace command ends. 731 // IF user press 'c' or 'C', Search/Replace command ends. 732 // input search string 733 // 734 Status = InputBarSetPrompt (L"Enter Search String: "); 735 if (EFI_ERROR (Status)) { 736 return Status; 737 } 738 739 Status = InputBarSetStringSize (40); 740 if (EFI_ERROR (Status)) { 741 return Status; 742 } 743 744 Status = InputBarRefresh (MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column); 745 StatusBarSetRefresh(); 746 747 // 748 // ESC 749 // 750 if (Status == EFI_NOT_READY) { 751 return EFI_SUCCESS; 752 } 753 // 754 // if just pressed enter 755 // 756 if (StrLen (InputBarGetString()) == 0) { 757 return EFI_SUCCESS; 758 } 759 760 Search = CatSPrint (NULL, L"%s", InputBarGetString()); 761 if (Search == NULL) { 762 return EFI_OUT_OF_RESOURCES; 763 } 764 765 SearchLen = StrLen (Search); 766 767 // 768 // input replace string 769 // 770 Status = InputBarSetPrompt (L"Replace With: "); 771 if (EFI_ERROR (Status)) { 772 return Status; 773 } 774 775 Status = InputBarSetStringSize (40); 776 if (EFI_ERROR (Status)) { 777 return Status; 778 } 779 780 Status = InputBarRefresh (MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column); 781 StatusBarSetRefresh(); 782 783 // 784 // ESC 785 // 786 if (Status == EFI_NOT_READY) { 787 return EFI_SUCCESS; 788 } 789 790 Replace = CatSPrint (NULL, L"%s", InputBarGetString()); 791 if (Replace == NULL) { 792 FreePool (Search); 793 return EFI_OUT_OF_RESOURCES; 794 } 795 796 ReplaceLen = StrLen (Replace); 797 798 First = TRUE; 799 ReplaceAll = FALSE; 800 do { 801 // 802 // since search may be continued to search multiple times 803 // so we need to backup editor each time 804 // 805 MainEditorBackup (); 806 807 if (First) { 808 Status = FileBufferSearch (Search, 0); 809 } else { 810 // 811 // if just replace, so skip this replace string 812 // if replace string is an empty string, so skip to next character 813 // 814 if (ReplaceOption) { 815 Status = FileBufferSearch (Search, (ReplaceLen == 0) ? 1 : ReplaceLen); 816 } else { 817 Status = FileBufferSearch (Search, SearchLen); 818 } 819 } 820 821 if (Status == EFI_NOT_FOUND) { 822 break; 823 } 824 // 825 // replace or not? 826 // 827 Status = InputBarSetPrompt (L"Replace (Yes/No/All/Cancel) ?"); 828 829 if (EFI_ERROR (Status)) { 830 FreePool (Search); 831 FreePool (Replace); 832 return Status; 833 } 834 835 Status = InputBarSetStringSize (1); 836 if (EFI_ERROR (Status)) { 837 FreePool (Search); 838 FreePool (Replace); 839 return Status; 840 } 841 842 Done = FALSE; 843 while (!Done) { 844 Status = InputBarRefresh (MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column); 845 StatusBarSetRefresh(); 846 847 // 848 // ESC pressed 849 // 850 if (Status == EFI_NOT_READY) { 851 FreePool (Search); 852 FreePool (Replace); 853 return EFI_SUCCESS; 854 } 855 856 switch (InputBarGetString()[0]) { 857 case L'y': 858 case L'Y': 859 Done = TRUE; 860 ReplaceOption = TRUE; 861 break; 862 863 case L'n': 864 case L'N': 865 Done = TRUE; 866 ReplaceOption = FALSE; 867 break; 868 869 case L'a': 870 case L'A': 871 Done = TRUE; 872 ReplaceOption = TRUE; 873 ReplaceAll = TRUE; 874 break; 875 876 case L'c': 877 case L'C': 878 FreePool (Search); 879 FreePool (Replace); 880 return EFI_SUCCESS; 881 882 } 883 // 884 // end of which 885 // 886 } 887 // 888 // end of while !Done 889 // Decide to Replace 890 // 891 if (ReplaceOption) { 892 // 893 // file is read-only 894 // 895 if (MainEditor.FileBuffer->ReadOnly) { 896 StatusBarSetStatusString (L"Read Only File Can Not Be Modified"); 897 return EFI_SUCCESS; 898 } 899 // 900 // replace all 901 // 902 if (ReplaceAll) { 903 Status = FileBufferReplaceAll (Search, Replace, 0); 904 FreePool (Search); 905 FreePool (Replace); 906 return Status; 907 } 908 // 909 // replace 910 // 911 Status = FileBufferReplace (Replace, SearchLen); 912 if (EFI_ERROR (Status)) { 913 FreePool (Search); 914 FreePool (Replace); 915 return Status; 916 } 917 } 918 // 919 // Find next 920 // 921 Status = InputBarSetPrompt (L"Find Next (Yes/No) ?"); 922 if (EFI_ERROR (Status)) { 923 FreePool (Search); 924 FreePool (Replace); 925 return Status; 926 } 927 928 Status = InputBarSetStringSize (1); 929 if (EFI_ERROR (Status)) { 930 FreePool (Search); 931 FreePool (Replace); 932 return Status; 933 } 934 935 Done = FALSE; 936 while (!Done) { 937 Status = InputBarRefresh (MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column); 938 StatusBarSetRefresh(); 939 940 // 941 // ESC pressed 942 // 943 if (Status == EFI_NOT_READY) { 944 FreePool (Search); 945 FreePool (Replace); 946 return EFI_SUCCESS; 947 } 948 949 switch (InputBarGetString()[0]) { 950 case L'y': 951 case L'Y': 952 Done = TRUE; 953 break; 954 955 case L'n': 956 case L'N': 957 FreePool (Search); 958 FreePool (Replace); 959 return EFI_SUCCESS; 960 961 } 962 // 963 // end of which 964 // 965 } 966 // 967 // end of while !Done 968 // 969 First = FALSE; 970 971 } while (1); 972 // 973 // end of do 974 // 975 FreePool (Search); 976 FreePool (Replace); 977 978 StatusBarSetStatusString (L"Search String Not Found"); 979 980 return EFI_SUCCESS; 981 } 982 983 /** 984 exit editor 985 986 @retval EFI_SUCCESS The operation was successful. 987 @retval EFI_OUT_OF_RESOURCES A memory allocation failed. 988 @retval EFI_LOAD_ERROR A load error occured. 989 **/ 990 EFI_STATUS 991 MainCommandExit ( 992 VOID 993 ) 994 { 995 EFI_STATUS Status; 996 997 // 998 // Below is the scenario of Exit command: 999 // 1. IF currently opened file is not modified, exit the editor and 1000 // Exit command ends. 1001 // IF currently opened file is modified, do Step 2 1002 // 1003 // 2. An Input Bar will be prompted: 1004 // "File modified. Save ( Yes/No/Cancel )?" 1005 // IF user press 'y' or 'Y', currently opened file will be saved 1006 // and Editor exits 1007 // IF user press 'n' or 'N', currently opened file will not be saved 1008 // and Editor exits. 1009 // IF user press 'c' or 'C' or ESC, Exit command ends. 1010 // if file has been modified, so will prompt user whether to save the changes 1011 // 1012 if (MainEditor.FileBuffer->FileModified) { 1013 1014 Status = InputBarSetPrompt (L"File modified. Save (Yes/No/Cancel) ? "); 1015 if (EFI_ERROR (Status)) { 1016 return Status; 1017 } 1018 1019 Status = InputBarSetStringSize (1); 1020 if (EFI_ERROR (Status)) { 1021 return Status; 1022 } 1023 1024 while (1) { 1025 Status = InputBarRefresh (MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column); 1026 StatusBarSetRefresh(); 1027 1028 // 1029 // ESC pressed 1030 // 1031 if (Status == EFI_NOT_READY) { 1032 return EFI_SUCCESS; 1033 } 1034 1035 switch (InputBarGetString()[0]) { 1036 case L'y': 1037 case L'Y': 1038 // 1039 // write file back to disk 1040 // 1041 Status = FileBufferSave (MainEditor.FileBuffer->FileName); 1042 if (!EFI_ERROR (Status)) { 1043 EditorExit = TRUE; 1044 } 1045 1046 return Status; 1047 1048 case L'n': 1049 case L'N': 1050 EditorExit = TRUE; 1051 return EFI_SUCCESS; 1052 1053 case L'c': 1054 case L'C': 1055 return EFI_SUCCESS; 1056 1057 } 1058 } 1059 } 1060 1061 EditorExit = TRUE; 1062 return EFI_SUCCESS; 1063 1064 } 1065 1066 /** 1067 move cursor to specified lines 1068 1069 @retval EFI_SUCCESS The operation was successful. 1070 **/ 1071 EFI_STATUS 1072 MainCommandGotoLine ( 1073 VOID 1074 ) 1075 { 1076 EFI_STATUS Status; 1077 UINTN Row; 1078 1079 // 1080 // Below is the scenario of Go To Line command: 1081 // 1. An Input Bar will be prompted : "Go To Line:". 1082 // IF user press ESC, Go To Line command ends. 1083 // IF user just press Enter, cursor remains unchanged. 1084 // IF user inputs line number, do Step 2. 1085 // 1086 // 2. IF input line number is valid, move cursor to the beginning 1087 // of specified line and Go To Line command ends. 1088 // IF input line number is invalid, a Status String will be prompted: 1089 // "No Such Line" and Go To Line command ends. 1090 // 1091 Status = InputBarSetPrompt (L"Go To Line: "); 1092 if (EFI_ERROR (Status)) { 1093 return Status; 1094 } 1095 // 1096 // line number's digit <= 6 1097 // 1098 Status = InputBarSetStringSize (6); 1099 if (EFI_ERROR (Status)) { 1100 return Status; 1101 } 1102 1103 Status = InputBarRefresh (MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column); 1104 StatusBarSetRefresh(); 1105 1106 // 1107 // press ESC 1108 // 1109 if (Status == EFI_NOT_READY) { 1110 return EFI_SUCCESS; 1111 } 1112 // 1113 // if JUST press enter 1114 // 1115 if (StrLen (InputBarGetString()) == 0) { 1116 return EFI_SUCCESS; 1117 } 1118 1119 Row = ShellStrToUintn (InputBarGetString()); 1120 1121 // 1122 // invalid line number 1123 // 1124 if (Row > MainEditor.FileBuffer->NumLines || Row <= 0) { 1125 StatusBarSetStatusString (L"No Such Line"); 1126 return EFI_SUCCESS; 1127 } 1128 // 1129 // move cursor to that line's start 1130 // 1131 FileBufferMovePosition (Row, 1); 1132 1133 return EFI_SUCCESS; 1134 } 1135 1136 /** 1137 Save current file to disk, you can save to current file name or 1138 save to another file name. 1139 1140 @retval EFI_SUCCESS The file was saved correctly. 1141 @retval EFI_OUT_OF_RESOURCES A memory allocation failed. 1142 @retval EFI_LOAD_ERROR A file access error occured. 1143 **/ 1144 EFI_STATUS 1145 MainCommandSaveFile ( 1146 VOID 1147 ) 1148 { 1149 EFI_STATUS Status; 1150 CHAR16 *FileName; 1151 BOOLEAN OldFile; 1152 CHAR16 *Str; 1153 SHELL_FILE_HANDLE FileHandle; 1154 EFI_FILE_INFO *Info; 1155 1156 // 1157 // This command will save currently opened file to disk. 1158 // You can choose save to another file name or just save to 1159 // current file name. 1160 // Below is the scenario of Save File command: 1161 // ( Suppose the old file name is A ) 1162 // 1. An Input Bar will be prompted: "File To Save: [ old file name]" 1163 // IF user press ESC, Save File command ends . 1164 // IF user press Enter, input file name will be A. 1165 // IF user inputs a new file name B, input file name will be B. 1166 // 1167 // 2. IF input file name is A, go to do Step 3. 1168 // IF input file name is B, go to do Step 4. 1169 // 1170 // 3. IF A is read only, Status Bar will show "Access Denied" and 1171 // Save File commands ends. 1172 // IF A is not read only, save file buffer to disk and remove modified 1173 // flag in Title Bar , then Save File command ends. 1174 // 1175 // 4. IF B does not exist, create this file and save file buffer to it. 1176 // Go to do Step 7. 1177 // IF B exits, do Step 5. 1178 // 1179 // 5.An Input Bar will be prompted: 1180 // "File Exists. Overwrite ( Yes/No/Cancel )?" 1181 // IF user press 'y' or 'Y', do Step 6. 1182 // IF user press 'n' or 'N', Save File commands ends. 1183 // IF user press 'c' or 'C' or ESC, Save File commands ends. 1184 // 1185 // 6. IF B is a read-only file, Status Bar will show "Access Denied" and 1186 // Save File commands ends. 1187 // IF B can be read and write, save file buffer to B. 1188 // 1189 // 7. Update File Name field in Title Bar to B and remove the modified 1190 // flag in Title Bar. 1191 // 1192 Str = CatSPrint (NULL, L"File to Save: [%s]", MainEditor.FileBuffer->FileName); 1193 if (Str == NULL) { 1194 return EFI_OUT_OF_RESOURCES; 1195 } 1196 1197 if (StrLen (Str) >= 50) { 1198 // 1199 // replace the long file name with "..." 1200 // 1201 Str[46] = L'.'; 1202 Str[47] = L'.'; 1203 Str[48] = L'.'; 1204 Str[49] = L']'; 1205 Str[50] = CHAR_NULL; 1206 } 1207 1208 Status = InputBarSetPrompt (Str); 1209 FreePool(Str); 1210 1211 if (EFI_ERROR (Status)) { 1212 return Status; 1213 } 1214 1215 1216 Status = InputBarSetStringSize (100); 1217 if (EFI_ERROR (Status)) { 1218 return Status; 1219 } 1220 // 1221 // get new file name 1222 // 1223 Status = InputBarRefresh (MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column); 1224 StatusBarSetRefresh(); 1225 1226 // 1227 // if user pressed ESC 1228 // 1229 if (Status == EFI_NOT_READY) { 1230 return EFI_SUCCESS; 1231 } 1232 1233 // 1234 // if just enter pressed, so think save to current file name 1235 // 1236 if (StrLen (InputBarGetString()) == 0) { 1237 FileName = CatSPrint (NULL, L"%s", MainEditor.FileBuffer->FileName); 1238 } else { 1239 FileName = CatSPrint (NULL, L"%s", InputBarGetString()); 1240 } 1241 1242 if (FileName == NULL) { 1243 return EFI_OUT_OF_RESOURCES; 1244 } 1245 1246 if (!IsValidFileName (FileName)) { 1247 StatusBarSetStatusString (L"Invalid File Name"); 1248 FreePool (FileName); 1249 return EFI_SUCCESS; 1250 } 1251 1252 OldFile = FALSE; 1253 1254 // 1255 // save to the old file 1256 // 1257 if (StringNoCaseCompare (&FileName, &MainEditor.FileBuffer->FileName) == 0) { 1258 OldFile = TRUE; 1259 } 1260 1261 if (OldFile) { 1262 // 1263 // if the file is read only, so can not write back to it. 1264 // 1265 if (MainEditor.FileBuffer->ReadOnly == TRUE) { 1266 StatusBarSetStatusString (L"Access Denied"); 1267 FreePool (FileName); 1268 return EFI_SUCCESS; 1269 } 1270 } else { 1271 // 1272 // if the file exists 1273 // 1274 if (ShellFileExists(FileName) != EFI_NOT_FOUND) { 1275 // 1276 // check for read only 1277 // 1278 Status = ShellOpenFileByName(FileName, &FileHandle, EFI_FILE_MODE_READ, 0); 1279 if (EFI_ERROR(Status)) { 1280 StatusBarSetStatusString (L"Open Failed"); 1281 FreePool (FileName); 1282 return EFI_SUCCESS; 1283 } 1284 1285 Info = ShellGetFileInfo(FileHandle); 1286 if (Info == NULL) { 1287 StatusBarSetStatusString (L"Access Denied"); 1288 FreePool (FileName); 1289 return (EFI_SUCCESS); 1290 } 1291 1292 if (Info->Attribute & EFI_FILE_READ_ONLY) { 1293 StatusBarSetStatusString (L"Access Denied - Read Only"); 1294 FreePool (Info); 1295 FreePool (FileName); 1296 return (EFI_SUCCESS); 1297 } 1298 FreePool (Info); 1299 1300 // 1301 // ask user whether to overwrite this file 1302 // 1303 Status = InputBarSetPrompt (L"File exists. Overwrite (Yes/No/Cancel) ? "); 1304 if (EFI_ERROR (Status)) { 1305 SHELL_FREE_NON_NULL (FileName); 1306 return Status; 1307 } 1308 1309 Status = InputBarSetStringSize (1); 1310 if (EFI_ERROR (Status)) { 1311 SHELL_FREE_NON_NULL (FileName); 1312 return Status; 1313 } 1314 1315 while (TRUE) { 1316 Status = InputBarRefresh (MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column); 1317 StatusBarSetRefresh(); 1318 1319 // 1320 // ESC pressed 1321 // 1322 if (Status == EFI_NOT_READY) { 1323 SHELL_FREE_NON_NULL (FileName); 1324 return EFI_SUCCESS; 1325 } 1326 1327 switch (InputBarGetString()[0]) { 1328 case L'y': 1329 case L'Y': 1330 break; 1331 1332 case L'n': 1333 case L'N': 1334 case L'c': 1335 case L'C': 1336 SHELL_FREE_NON_NULL (FileName); 1337 return EFI_SUCCESS; 1338 } // end switch 1339 } // while (!done) 1340 } // file does exist 1341 } // if old file name same 1342 1343 // 1344 // save file to disk with specified name 1345 // 1346 FileBufferSetModified(); 1347 Status = FileBufferSave (FileName); 1348 SHELL_FREE_NON_NULL (FileName); 1349 1350 return Status; 1351 } 1352 1353 /** 1354 Show help information for the editor. 1355 1356 @retval EFI_SUCCESS The operation was successful. 1357 **/ 1358 EFI_STATUS 1359 MainCommandDisplayHelp ( 1360 VOID 1361 ) 1362 { 1363 INT32 CurrentLine; 1364 CHAR16 *InfoString; 1365 EFI_INPUT_KEY Key; 1366 1367 // 1368 // print helpInfo 1369 // 1370 for (CurrentLine = 0; 0 != MainMenuHelpInfo[CurrentLine]; CurrentLine++) { 1371 InfoString = HiiGetString(gShellDebug1HiiHandle, MainMenuHelpInfo[CurrentLine], NULL); 1372 ShellPrintEx (0, CurrentLine+1, L"%E%s%N", InfoString); 1373 } 1374 1375 // 1376 // scan for ctrl+w 1377 // 1378 do { 1379 gST->ConIn->ReadKeyStroke (gST->ConIn, &Key); 1380 } while(SCAN_CONTROL_W != Key.UnicodeChar); 1381 1382 // 1383 // update screen with file buffer's info 1384 // 1385 FileBufferRestorePosition (); 1386 FileBufferNeedRefresh = TRUE; 1387 FileBufferOnlyLineNeedRefresh = FALSE; 1388 FileBufferRefresh (); 1389 1390 return EFI_SUCCESS; 1391 } 1392 1393 EFI_EDITOR_COLOR_ATTRIBUTES OriginalColors; 1394 INTN OriginalMode; 1395 1396 1397 // 1398 // basic initialization for MainEditor 1399 // 1400 EFI_EDITOR_GLOBAL_EDITOR MainEditorConst = { 1401 &FileBuffer, 1402 { 1403 {0, 0} 1404 }, 1405 { 1406 0, 1407 0 1408 }, 1409 NULL, 1410 FALSE, 1411 NULL 1412 }; 1413 1414 /** 1415 The initialization function for MainEditor. 1416 1417 @retval EFI_SUCCESS The operation was successful. 1418 @retval EFI_LOAD_ERROR A load error occured. 1419 **/ 1420 EFI_STATUS 1421 MainEditorInit ( 1422 VOID 1423 ) 1424 { 1425 EFI_STATUS Status; 1426 EFI_HANDLE *HandleBuffer; 1427 UINTN HandleCount; 1428 UINTN Index; 1429 1430 // 1431 // basic initialization 1432 // 1433 CopyMem (&MainEditor, &MainEditorConst, sizeof (MainEditor)); 1434 1435 // 1436 // set screen attributes 1437 // 1438 MainEditor.ColorAttributes.Colors.Foreground = gST->ConOut->Mode->Attribute & 0x000000ff; 1439 1440 MainEditor.ColorAttributes.Colors.Background = (UINT8) (gST->ConOut->Mode->Attribute >> 4); 1441 OriginalColors = MainEditor.ColorAttributes.Colors; 1442 1443 OriginalMode = gST->ConOut->Mode->Mode; 1444 1445 // 1446 // query screen size 1447 // 1448 gST->ConOut->QueryMode ( 1449 gST->ConOut, 1450 gST->ConOut->Mode->Mode, 1451 &(MainEditor.ScreenSize.Column), 1452 &(MainEditor.ScreenSize.Row) 1453 ); 1454 1455 // 1456 // Find mouse in System Table ConsoleInHandle 1457 // 1458 Status = gBS->HandleProtocol ( 1459 gST->ConIn, 1460 &gEfiSimplePointerProtocolGuid, 1461 (VOID**)&MainEditor.MouseInterface 1462 ); 1463 if (EFI_ERROR (Status)) { 1464 // 1465 // If there is no Simple Pointer Protocol on System Table 1466 // 1467 HandleBuffer = NULL; 1468 MainEditor.MouseInterface = NULL; 1469 Status = gBS->LocateHandleBuffer ( 1470 ByProtocol, 1471 &gEfiSimplePointerProtocolGuid, 1472 NULL, 1473 &HandleCount, 1474 &HandleBuffer 1475 ); 1476 if (!EFI_ERROR (Status) && HandleCount > 0) { 1477 // 1478 // Try to find the first available mouse device 1479 // 1480 for (Index = 0; Index < HandleCount; Index++) { 1481 Status = gBS->HandleProtocol ( 1482 HandleBuffer[Index], 1483 &gEfiSimplePointerProtocolGuid, 1484 (VOID**)&MainEditor.MouseInterface 1485 ); 1486 if (!EFI_ERROR (Status)) { 1487 break; 1488 } 1489 } 1490 } 1491 if (HandleBuffer != NULL) { 1492 FreePool (HandleBuffer); 1493 } 1494 } 1495 1496 if (!EFI_ERROR (Status) && MainEditor.MouseInterface != NULL) { 1497 MainEditor.MouseAccumulatorX = 0; 1498 MainEditor.MouseAccumulatorY = 0; 1499 MainEditor.MouseSupported = TRUE; 1500 } 1501 1502 // 1503 // below will call the five components' init function 1504 // 1505 Status = MainTitleBarInit (L"UEFI EDIT"); 1506 if (EFI_ERROR (Status)) { 1507 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_EDIT_LIBEDITOR_TITLEBAR), gShellDebug1HiiHandle); 1508 return EFI_LOAD_ERROR; 1509 } 1510 1511 Status = ControlHotKeyInit (MainControlBasedMenuFunctions); 1512 Status = MenuBarInit (MainMenuItems); 1513 if (EFI_ERROR (Status)) { 1514 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_EDIT_LIBEDITOR_MAINMENU), gShellDebug1HiiHandle); 1515 return EFI_LOAD_ERROR; 1516 } 1517 1518 Status = StatusBarInit (); 1519 if (EFI_ERROR (Status)) { 1520 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_EDIT_LIBEDITOR_STATUSBAR), gShellDebug1HiiHandle); 1521 return EFI_LOAD_ERROR; 1522 } 1523 1524 InputBarInit (); 1525 1526 Status = FileBufferInit (); 1527 if (EFI_ERROR (Status)) { 1528 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_EDIT_LIBEDITOR_FILEBUFFER), gShellDebug1HiiHandle); 1529 return EFI_LOAD_ERROR; 1530 } 1531 // 1532 // clear whole screen and enable cursor 1533 // 1534 gST->ConOut->ClearScreen (gST->ConOut); 1535 gST->ConOut->EnableCursor (gST->ConOut, TRUE); 1536 1537 // 1538 // initialize EditorFirst and EditorExit 1539 // 1540 EditorFirst = TRUE; 1541 EditorExit = FALSE; 1542 EditorMouseAction = FALSE; 1543 1544 return EFI_SUCCESS; 1545 } 1546 1547 /** 1548 The cleanup function for MainEditor. 1549 1550 @retval EFI_SUCCESS The operation was successful. 1551 @retval EFI_LOAD_ERROR A load error occured. 1552 **/ 1553 EFI_STATUS 1554 MainEditorCleanup ( 1555 VOID 1556 ) 1557 { 1558 EFI_STATUS Status; 1559 1560 // 1561 // call the five components' cleanup function 1562 // if error, do not exit 1563 // just print some warning 1564 // 1565 MainTitleBarCleanup(); 1566 StatusBarCleanup(); 1567 InputBarCleanup(); 1568 MenuBarCleanup (); 1569 1570 Status = FileBufferCleanup (); 1571 if (EFI_ERROR (Status)) { 1572 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_EDIT_LIBEDITOR_FILEBUFFER_CLEANUP), gShellDebug1HiiHandle); 1573 } 1574 // 1575 // restore old mode 1576 // 1577 if (OriginalMode != gST->ConOut->Mode->Mode) { 1578 gST->ConOut->SetMode (gST->ConOut, OriginalMode); 1579 } 1580 // 1581 // restore old screen color 1582 // 1583 gST->ConOut->SetAttribute ( 1584 gST->ConOut, 1585 EFI_TEXT_ATTR (OriginalColors.Foreground, OriginalColors.Background) 1586 ); 1587 1588 gST->ConOut->ClearScreen (gST->ConOut); 1589 1590 return EFI_SUCCESS; 1591 } 1592 1593 /** 1594 Refresh the main editor component. 1595 **/ 1596 VOID 1597 MainEditorRefresh ( 1598 VOID 1599 ) 1600 { 1601 // 1602 // The Stall value is from experience. NOT from spec. avoids 'flicker' 1603 // 1604 gBS->Stall (50); 1605 1606 // 1607 // call the components refresh function 1608 // 1609 if (EditorFirst 1610 || StrCmp (FileBufferBackupVar.FileName, FileBuffer.FileName) != 0 1611 || FileBufferBackupVar.FileType != FileBuffer.FileType 1612 || FileBufferBackupVar.FileModified != FileBuffer.FileModified 1613 || FileBufferBackupVar.ReadOnly != FileBuffer.ReadOnly) { 1614 1615 MainTitleBarRefresh (MainEditor.FileBuffer->FileName, MainEditor.FileBuffer->FileType, MainEditor.FileBuffer->ReadOnly, MainEditor.FileBuffer->FileModified, MainEditor.ScreenSize.Column, MainEditor.ScreenSize.Row, 0, 0); 1616 FileBufferRestorePosition (); 1617 } 1618 1619 if (EditorFirst 1620 || FileBufferBackupVar.FilePosition.Row != FileBuffer.FilePosition.Row 1621 || FileBufferBackupVar.FilePosition.Column != FileBuffer.FilePosition.Column 1622 || FileBufferBackupVar.ModeInsert != FileBuffer.ModeInsert 1623 || StatusBarGetRefresh()) { 1624 1625 StatusBarRefresh (EditorFirst, MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column, MainEditor.FileBuffer->FilePosition.Row, MainEditor.FileBuffer->FilePosition.Column, MainEditor.FileBuffer->ModeInsert); 1626 FileBufferRestorePosition (); 1627 } 1628 1629 if (EditorFirst) { 1630 FileBufferRestorePosition (); 1631 } 1632 1633 FileBufferRefresh (); 1634 1635 // 1636 // EditorFirst is now set to FALSE 1637 // 1638 EditorFirst = FALSE; 1639 } 1640 1641 /** 1642 Get's the resultant location of the cursor based on the relative movement of the Mouse. 1643 1644 @param[in] GuidX The relative mouse movement. 1645 1646 @return The X location of the mouse. 1647 **/ 1648 INT32 1649 GetTextX ( 1650 IN INT32 GuidX 1651 ) 1652 { 1653 INT32 Gap; 1654 1655 MainEditor.MouseAccumulatorX += GuidX; 1656 Gap = (MainEditor.MouseAccumulatorX * (INT32) MainEditor.ScreenSize.Column) / (INT32) (50 * (INT32) MainEditor.MouseInterface->Mode->ResolutionX); 1657 MainEditor.MouseAccumulatorX = (MainEditor.MouseAccumulatorX * (INT32) MainEditor.ScreenSize.Column) % (INT32) (50 * (INT32) MainEditor.MouseInterface->Mode->ResolutionX); 1658 MainEditor.MouseAccumulatorX = MainEditor.MouseAccumulatorX / (INT32) MainEditor.ScreenSize.Column; 1659 return Gap; 1660 } 1661 1662 /** 1663 Get's the resultant location of the cursor based on the relative movement of the Mouse. 1664 1665 @param[in] GuidY The relative mouse movement. 1666 1667 @return The Y location of the mouse. 1668 **/ 1669 INT32 1670 GetTextY ( 1671 IN INT32 GuidY 1672 ) 1673 { 1674 INT32 Gap; 1675 1676 MainEditor.MouseAccumulatorY += GuidY; 1677 Gap = (MainEditor.MouseAccumulatorY * (INT32) MainEditor.ScreenSize.Row) / (INT32) (50 * (INT32) MainEditor.MouseInterface->Mode->ResolutionY); 1678 MainEditor.MouseAccumulatorY = (MainEditor.MouseAccumulatorY * (INT32) MainEditor.ScreenSize.Row) % (INT32) (50 * (INT32) MainEditor.MouseInterface->Mode->ResolutionY); 1679 MainEditor.MouseAccumulatorY = MainEditor.MouseAccumulatorY / (INT32) MainEditor.ScreenSize.Row; 1680 1681 return Gap; 1682 } 1683 1684 /** 1685 Support mouse movement. Move the cursor. 1686 1687 @param[in] MouseState The current mouse state. 1688 1689 @retval EFI_SUCCESS The operation was successful. 1690 @retval EFI_NOT_FOUND There was no mouse support found. 1691 **/ 1692 EFI_STATUS 1693 MainEditorHandleMouseInput ( 1694 IN EFI_SIMPLE_POINTER_STATE MouseState 1695 ) 1696 { 1697 1698 INT32 TextX; 1699 INT32 TextY; 1700 UINTN FRow; 1701 UINTN FCol; 1702 1703 LIST_ENTRY *Link; 1704 EFI_EDITOR_LINE *Line; 1705 1706 UINTN Index; 1707 BOOLEAN Action; 1708 1709 // 1710 // mouse action means: 1711 // mouse movement 1712 // mouse left button 1713 // 1714 Action = FALSE; 1715 1716 // 1717 // have mouse movement 1718 // 1719 if (MouseState.RelativeMovementX || MouseState.RelativeMovementY) { 1720 // 1721 // handle 1722 // 1723 TextX = GetTextX (MouseState.RelativeMovementX); 1724 TextY = GetTextY (MouseState.RelativeMovementY); 1725 1726 FileBufferAdjustMousePosition (TextX, TextY); 1727 1728 Action = TRUE; 1729 1730 } 1731 1732 // 1733 // if left button pushed down 1734 // 1735 if (MouseState.LeftButton) { 1736 1737 FCol = MainEditor.FileBuffer->MousePosition.Column - 1 + 1; 1738 1739 FRow = MainEditor.FileBuffer->FilePosition.Row + 1740 MainEditor.FileBuffer->MousePosition.Row - 1741 MainEditor.FileBuffer->DisplayPosition.Row; 1742 1743 // 1744 // beyond the file line length 1745 // 1746 if (MainEditor.FileBuffer->NumLines < FRow) { 1747 FRow = MainEditor.FileBuffer->NumLines; 1748 } 1749 1750 Link = MainEditor.FileBuffer->ListHead->ForwardLink; 1751 for (Index = 0; Index < FRow - 1; Index++) { 1752 Link = Link->ForwardLink; 1753 } 1754 1755 Line = CR (Link, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE); 1756 1757 // 1758 // beyond the line's column length 1759 // 1760 if (FCol > Line->Size + 1) { 1761 FCol = Line->Size + 1; 1762 } 1763 1764 FileBufferMovePosition (FRow, FCol); 1765 1766 MainEditor.FileBuffer->MousePosition.Row = MainEditor.FileBuffer->DisplayPosition.Row; 1767 1768 MainEditor.FileBuffer->MousePosition.Column = MainEditor.FileBuffer->DisplayPosition.Column; 1769 1770 Action = TRUE; 1771 } 1772 // 1773 // mouse has action 1774 // 1775 if (Action) { 1776 return EFI_SUCCESS; 1777 } 1778 1779 // 1780 // no mouse action 1781 // 1782 return EFI_NOT_FOUND; 1783 } 1784 1785 /** 1786 Handle user key input. This routes to other functions for the actions. 1787 1788 @retval EFI_SUCCESS The operation was successful. 1789 @retval EFI_LOAD_ERROR A load error occured. 1790 @retval EFI_OUT_OF_RESOURCES A memory allocation failed. 1791 **/ 1792 EFI_STATUS 1793 MainEditorKeyInput ( 1794 VOID 1795 ) 1796 { 1797 EFI_INPUT_KEY Key; 1798 EFI_STATUS Status; 1799 EFI_SIMPLE_POINTER_STATE MouseState; 1800 1801 do { 1802 1803 Status = EFI_SUCCESS; 1804 EditorMouseAction = FALSE; 1805 1806 // 1807 // backup some key elements, so that can aVOID some refresh work 1808 // 1809 MainEditorBackup (); 1810 1811 // 1812 // change priority of checking mouse/keyboard activity dynamically 1813 // so prevent starvation of keyboard. 1814 // if last time, mouse moves then this time check keyboard 1815 // 1816 if (MainEditor.MouseSupported) { 1817 Status = MainEditor.MouseInterface->GetState ( 1818 MainEditor.MouseInterface, 1819 &MouseState 1820 ); 1821 if (!EFI_ERROR (Status)) { 1822 1823 Status = MainEditorHandleMouseInput (MouseState); 1824 1825 if (!EFI_ERROR (Status)) { 1826 EditorMouseAction = TRUE; 1827 FileBufferMouseNeedRefresh = TRUE; 1828 } else if (Status == EFI_LOAD_ERROR) { 1829 StatusBarSetStatusString (L"Invalid Mouse Movement "); 1830 } 1831 } 1832 } 1833 1834 Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key); 1835 if (!EFI_ERROR (Status)) { 1836 // 1837 // dispatch to different components' key handling function 1838 // so not everywhere has to set this variable 1839 // 1840 FileBufferMouseNeedRefresh = TRUE; 1841 // 1842 // clear previous status string 1843 // 1844 StatusBarSetRefresh(); 1845 1846 // 1847 // dispatch to different components' key handling function 1848 // 1849 if (EFI_NOT_FOUND != MenuBarDispatchControlHotKey(&Key)) { 1850 Status = EFI_SUCCESS; 1851 } else if ((Key.ScanCode == SCAN_NULL) || ((Key.ScanCode >= SCAN_UP) && (Key.ScanCode <= SCAN_PAGE_DOWN))) { 1852 Status = FileBufferHandleInput (&Key); 1853 } else if ((Key.ScanCode >= SCAN_F1) && (Key.ScanCode <= SCAN_F12)) { 1854 Status = MenuBarDispatchFunctionKey (&Key); 1855 } else { 1856 StatusBarSetStatusString (L"Unknown Command"); 1857 FileBufferMouseNeedRefresh = FALSE; 1858 } 1859 1860 if (Status != EFI_SUCCESS && Status != EFI_OUT_OF_RESOURCES) { 1861 // 1862 // not already has some error status 1863 // 1864 if (StatusBarGetString() != NULL && StrCmp (L"", StatusBarGetString()) == 0) { 1865 StatusBarSetStatusString (L"Disk Error. Try Again"); 1866 } 1867 } 1868 1869 } 1870 // 1871 // after handling, refresh editor 1872 // 1873 MainEditorRefresh (); 1874 1875 } while (Status != EFI_OUT_OF_RESOURCES && !EditorExit); 1876 1877 return Status; 1878 } 1879 1880 /** 1881 Set clipboard 1882 1883 @param[in] Line A pointer to the line to be set to clipboard 1884 1885 @retval EFI_SUCCESS The operation was successful. 1886 @retval EFI_OUT_OF_RESOURCES A memory allocation failed. 1887 **/ 1888 EFI_STATUS 1889 MainEditorSetCutLine ( 1890 EFI_EDITOR_LINE *Line 1891 ) 1892 { 1893 if (Line == NULL) { 1894 return EFI_SUCCESS; 1895 } 1896 1897 if (MainEditor.CutLine != NULL) { 1898 // 1899 // free the old clipboard 1900 // 1901 LineFree (MainEditor.CutLine); 1902 } 1903 // 1904 // duplicate the line to clipboard 1905 // 1906 MainEditor.CutLine = LineDup (Line); 1907 if (MainEditor.CutLine == NULL) { 1908 return EFI_OUT_OF_RESOURCES; 1909 } 1910 1911 return EFI_SUCCESS; 1912 } 1913 1914 /** 1915 Backup function for MainEditor 1916 1917 @retval EFI_SUCCESS The operation was successful. 1918 **/ 1919 EFI_STATUS 1920 MainEditorBackup ( 1921 VOID 1922 ) 1923 { 1924 FileBufferBackup (); 1925 1926 return EFI_SUCCESS; 1927 } 1928