FileBuffer.c 77 KB

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