Home | History | Annotate | Download | only in Edit
      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