MainTextEditor.c 51 KB

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