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