]> git.proxmox.com Git - mirror_edk2.git/blame - ShellPkg/Application/Shell/FileHandleWrappers.c
ShellPkg: TAB logic incorrectly chops out fs0: when typing fs0:<TAB>
[mirror_edk2.git] / ShellPkg / Application / Shell / FileHandleWrappers.c
CommitLineData
a405b86d 1/** @file\r
2 EFI_FILE_PROTOCOL wrappers for other items (Like Environment Variables,\r
3 StdIn, StdOut, StdErr, etc...).\r
4\r
9ed21946 5 Copyright 2016 Dell Inc.\r
9eec4d38 6 Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>\r
c011b6c9 7 (C) Copyright 2013 Hewlett-Packard Development Company, L.P.<BR>\r
a405b86d 8 This program and the accompanying materials\r
9 are licensed and made available under the terms and conditions of the BSD License\r
10 which accompanies this distribution. The full text of the license may be found at\r
11 http://opensource.org/licenses/bsd-license.php\r
12\r
13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
15\r
16**/\r
17\r
18#include "Shell.h"\r
19#include "FileHandleInternal.h"\r
20\r
c8d9d0e2
JD
21#define MEM_WRITE_REALLOC_OVERHEAD 1024\r
22\r
a405b86d 23/**\r
24 File style interface for console (Open). \r
25 \r
26 @param[in] This Ignored.\r
27 @param[out] NewHandle Ignored.\r
28 @param[in] FileName Ignored.\r
29 @param[in] OpenMode Ignored.\r
30 @param[in] Attributes Ignored.\r
31 \r
32 @retval EFI_NOT_FOUND\r
33**/\r
34EFI_STATUS\r
35EFIAPI\r
36FileInterfaceOpenNotFound(\r
37 IN EFI_FILE_PROTOCOL *This,\r
38 OUT EFI_FILE_PROTOCOL **NewHandle,\r
39 IN CHAR16 *FileName,\r
40 IN UINT64 OpenMode,\r
41 IN UINT64 Attributes\r
42 )\r
43{\r
44 return (EFI_NOT_FOUND);\r
45}\r
46\r
47/**\r
48 File style interface for console (Close, Delete, & Flush)\r
49 \r
50 @param[in] This Ignored.\r
51 \r
52 @retval EFI_SUCCESS\r
53**/\r
54EFI_STATUS\r
55EFIAPI\r
56FileInterfaceNopGeneric(\r
57 IN EFI_FILE_PROTOCOL *This\r
58 )\r
59{\r
60 return (EFI_SUCCESS);\r
61}\r
62\r
63/**\r
64 File style interface for console (GetPosition).\r
65\r
66 @param[in] This Ignored.\r
67 @param[out] Position Ignored.\r
68 \r
69 @retval EFI_UNSUPPORTED\r
70**/\r
71EFI_STATUS\r
72EFIAPI\r
73FileInterfaceNopGetPosition(\r
74 IN EFI_FILE_PROTOCOL *This,\r
75 OUT UINT64 *Position\r
76 )\r
77{\r
78 return (EFI_UNSUPPORTED);\r
79}\r
80\r
81/**\r
82 File style interface for console (SetPosition).\r
83 \r
84 @param[in] This Ignored.\r
85 @param[in] Position Ignored.\r
86 \r
87 @retval EFI_UNSUPPORTED\r
88**/\r
89EFI_STATUS\r
90EFIAPI\r
91FileInterfaceNopSetPosition(\r
92 IN EFI_FILE_PROTOCOL *This,\r
93 IN UINT64 Position\r
94 )\r
95{\r
96 return (EFI_UNSUPPORTED);\r
97}\r
98\r
99/**\r
100 File style interface for console (GetInfo).\r
101 \r
4ff7e37b
ED
102 @param[in] This Ignored.\r
103 @param[in] InformationType Ignored.\r
104 @param[in, out] BufferSize Ignored.\r
105 @param[out] Buffer Ignored.\r
a405b86d 106 \r
107 @retval EFI_UNSUPPORTED\r
108**/\r
109EFI_STATUS\r
110EFIAPI\r
111FileInterfaceNopGetInfo(\r
112 IN EFI_FILE_PROTOCOL *This,\r
113 IN EFI_GUID *InformationType,\r
114 IN OUT UINTN *BufferSize,\r
115 OUT VOID *Buffer\r
116 )\r
117{\r
118 return (EFI_UNSUPPORTED);\r
119}\r
120\r
121/**\r
122 File style interface for console (SetInfo).\r
123 \r
124 @param[in] This Ignored.\r
125 @param[in] InformationType Ignored.\r
126 @param[in] BufferSize Ignored.\r
127 @param[in] Buffer Ignored.\r
128 \r
129 @retval EFI_UNSUPPORTED\r
130**/\r
131EFI_STATUS\r
132EFIAPI\r
133FileInterfaceNopSetInfo(\r
134 IN EFI_FILE_PROTOCOL *This,\r
135 IN EFI_GUID *InformationType,\r
136 IN UINTN BufferSize,\r
137 IN VOID *Buffer\r
138 )\r
139{\r
140 return (EFI_UNSUPPORTED);\r
141}\r
142\r
143/**\r
144 File style interface for StdOut (Write).\r
145\r
146 Writes data to the screen.\r
147 \r
4ff7e37b
ED
148 @param[in] This The pointer to the EFI_FILE_PROTOCOL object.\r
149 @param[in, out] BufferSize Size in bytes of Buffer.\r
150 @param[in] Buffer The pointer to the buffer to write.\r
a405b86d 151 \r
152 @retval EFI_UNSUPPORTED No output console is supported.\r
153 @return A return value from gST->ConOut->OutputString.\r
154**/\r
155EFI_STATUS\r
156EFIAPI\r
157FileInterfaceStdOutWrite(\r
158 IN EFI_FILE_PROTOCOL *This,\r
159 IN OUT UINTN *BufferSize,\r
160 IN VOID *Buffer\r
161 )\r
162{\r
163 if (ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoConsoleOut) {\r
164 return (EFI_UNSUPPORTED);\r
a405b86d 165 }\r
d73fc181
JD
166 if (*((CHAR16 *)Buffer) == gUnicodeFileTag) {\r
167 return (gST->ConOut->OutputString(gST->ConOut, (CHAR16 *)Buffer + 1));\r
168 }\r
169 return (gST->ConOut->OutputString(gST->ConOut, Buffer));\r
a405b86d 170}\r
171\r
172/**\r
173 File style interface for StdIn (Write).\r
174 \r
4ff7e37b
ED
175 @param[in] This Ignored.\r
176 @param[in, out] BufferSize Ignored.\r
177 @param[in] Buffer Ignored.\r
a405b86d 178 \r
179 @retval EFI_UNSUPPORTED\r
180**/\r
181EFI_STATUS\r
182EFIAPI\r
183FileInterfaceStdInWrite(\r
733f138d 184 IN EFI_FILE_PROTOCOL *This,\r
185 IN OUT UINTN *BufferSize,\r
186 IN VOID *Buffer\r
a405b86d 187 )\r
188{\r
189 return (EFI_UNSUPPORTED);\r
190}\r
191\r
192/**\r
193 File style interface for console StdErr (Write).\r
194\r
195 Writes error to the error output.\r
196 \r
4ff7e37b
ED
197 @param[in] This The pointer to the EFI_FILE_PROTOCOL object.\r
198 @param[in, out] BufferSize Size in bytes of Buffer.\r
199 @param[in] Buffer The pointer to the buffer to write.\r
a405b86d 200 \r
201 @return A return value from gST->StdErr->OutputString.\r
202**/\r
203EFI_STATUS\r
204EFIAPI\r
205FileInterfaceStdErrWrite(\r
206 IN EFI_FILE_PROTOCOL *This,\r
207 IN OUT UINTN *BufferSize,\r
208 IN VOID *Buffer\r
209 )\r
210{\r
211 return (gST->StdErr->OutputString(gST->StdErr, Buffer));\r
212}\r
213\r
214/**\r
215 File style interface for console StdOut (Read).\r
216 \r
4ff7e37b
ED
217 @param[in] This Ignored.\r
218 @param[in, out] BufferSize Ignored.\r
219 @param[out] Buffer Ignored.\r
a405b86d 220 \r
221 @retval EFI_UNSUPPORTED\r
222**/\r
223EFI_STATUS\r
224EFIAPI\r
225FileInterfaceStdOutRead(\r
226 IN EFI_FILE_PROTOCOL *This,\r
227 IN OUT UINTN *BufferSize,\r
228 OUT VOID *Buffer\r
229 )\r
230{\r
231 return (EFI_UNSUPPORTED);\r
232}\r
233\r
234/**\r
235 File style interface for console StdErr (Read).\r
236 \r
4ff7e37b
ED
237 @param[in] This Ignored.\r
238 @param[in, out] BufferSize Ignored.\r
239 @param[out] Buffer Ignored.\r
a405b86d 240 \r
733f138d 241 @retval EFI_UNSUPPORTED Always.\r
a405b86d 242**/\r
243EFI_STATUS\r
244EFIAPI\r
245FileInterfaceStdErrRead(\r
246 IN EFI_FILE_PROTOCOL *This,\r
247 IN OUT UINTN *BufferSize,\r
248 OUT VOID *Buffer\r
249 )\r
250{\r
251 return (EFI_UNSUPPORTED);\r
252}\r
253\r
254/**\r
255 File style interface for NUL file (Read).\r
256 \r
4ff7e37b
ED
257 @param[in] This Ignored.\r
258 @param[in, out] BufferSize Poiner to 0 upon return.\r
259 @param[out] Buffer Ignored.\r
a405b86d 260 \r
733f138d 261 @retval EFI_SUCCESS Always.\r
a405b86d 262**/\r
263EFI_STATUS\r
264EFIAPI\r
265FileInterfaceNulRead(\r
733f138d 266 IN EFI_FILE_PROTOCOL *This,\r
267 IN OUT UINTN *BufferSize,\r
268 OUT VOID *Buffer\r
a405b86d 269 )\r
270{\r
a49f6a2f 271 *BufferSize = 0;\r
a405b86d 272 return (EFI_SUCCESS);\r
273}\r
274\r
275/**\r
276 File style interface for NUL file (Write).\r
277 \r
4ff7e37b
ED
278 @param[in] This Ignored.\r
279 @param[in, out] BufferSize Ignored.\r
280 @param[in] Buffer Ignored.\r
a405b86d 281 \r
282 @retval EFI_SUCCESS\r
283**/\r
284EFI_STATUS\r
285EFIAPI\r
286FileInterfaceNulWrite(\r
287 IN EFI_FILE_PROTOCOL *This,\r
288 IN OUT UINTN *BufferSize,\r
289 IN VOID *Buffer\r
290 )\r
291{\r
292 return (EFI_SUCCESS);\r
293}\r
294\r
9fcfa150
RN
295/**\r
296 Create the TAB completion list.\r
297\r
298 @param[in] InputString The command line to expand.\r
299 @param[in] StringLen Length of the command line.\r
300 @param[in] BufferSize Buffer size.\r
301 @param[out] TabCompletionList Return the TAB completion list.\r
302 @param[out] TabUpdatePos Return the TAB update position.\r
303**/\r
304EFI_STATUS\r
305EFIAPI\r
306CreateTabCompletionList (\r
307 IN CONST CHAR16 *InputString,\r
308 IN CONST UINTN StringLen, \r
309 IN CONST UINTN BufferSize,\r
310 IN OUT EFI_SHELL_FILE_INFO **TabCompletionList,\r
311 IN OUT UINTN *TabUpdatePos\r
312)\r
313{\r
314 BOOLEAN InQuotation;\r
315 UINTN TabPos;\r
316 UINTN Index;\r
317 CONST CHAR16 *Cwd;\r
318 EFI_STATUS Status;\r
319 CHAR16 *TabStr;\r
320 EFI_SHELL_FILE_INFO *FileList;\r
321 EFI_SHELL_FILE_INFO *FileInfo;\r
322 EFI_SHELL_FILE_INFO *TempFileInfo;\r
323\r
324 //\r
325 // Allocate buffers\r
326 //\r
327 TabStr = AllocateZeroPool (BufferSize);\r
328 if (TabStr == NULL) {\r
329 return EFI_OUT_OF_RESOURCES;\r
330 }\r
331\r
332 //\r
333 // handle auto complete of file and directory names...\r
334 // E.g.: cd fs0:\EFI\Bo<TAB>\r
335 // ^ ^\r
336 // TabPos TabUpdatePos\r
337 //\r
338 TabPos = 0;\r
339 *TabUpdatePos = 0;\r
340 FileList = NULL;\r
341 InQuotation = FALSE;\r
342 for (Index = 0; Index < StringLen; Index++) {\r
343 switch (InputString[Index]) {\r
344 case L'\"':\r
345 InQuotation = (BOOLEAN) (!InQuotation);\r
346 break;\r
347\r
348 case L' ':\r
349 if (!InQuotation) {\r
350 TabPos = Index + 1;\r
351 *TabUpdatePos = TabPos;\r
352 }\r
353 break;\r
354\r
355 case L':':\r
356 //\r
357 // handle the case "fs0:<TAB>"\r
358 // Update the TabUpdatePos as well.\r
359 //\r
360 case L'\\':\r
361 *TabUpdatePos = Index + 1;\r
362 break;\r
363\r
364 default:\r
365 break;\r
366 }\r
367 }\r
368\r
369 if (StrStr (InputString + TabPos, L":") == NULL) {\r
370 //\r
371 // If file path doesn't contain ":", it's a path relative to current directory.\r
372 //\r
373 Cwd = ShellInfoObject.NewEfiShellProtocol->GetCurDir (NULL);\r
374 if (Cwd != NULL) {\r
375 StrnCpyS (TabStr, (BufferSize) / sizeof (CHAR16), Cwd, (BufferSize) / sizeof (CHAR16) - 1);\r
376 if (InputString[TabPos] != L'\\') {\r
377 StrCatS (TabStr, (BufferSize) / sizeof (CHAR16), L"\\");\r
378 }\r
379 }\r
380 }\r
381 StrnCatS (TabStr, (BufferSize) / sizeof (CHAR16), InputString + TabPos, StringLen - TabPos);\r
382 StrnCatS (TabStr, (BufferSize) / sizeof (CHAR16), L"*", (BufferSize) / sizeof (CHAR16) - 1 - StrLen (TabStr));\r
383 Status = ShellInfoObject.NewEfiShellProtocol->FindFiles(TabStr, &FileList);\r
384\r
385 //\r
386 // Filter out the non-directory for "CD" command\r
387 // Filter "." and ".." for all\r
388 //\r
389 if (!EFI_ERROR (Status) && FileList != NULL) {\r
390 //\r
391 // Skip the spaces in the beginning\r
392 //\r
393 while (*InputString == L' ') {\r
394 InputString++;\r
395 }\r
396\r
397 for (FileInfo = (EFI_SHELL_FILE_INFO *) GetFirstNode (&FileList->Link); !IsNull (&FileList->Link, &FileInfo->Link); ) {\r
398 if (((StrCmp (FileInfo->FileName, L".") == 0) || (StrCmp (FileInfo->FileName, L"..") == 0)) ||\r
399 (((InputString[0] == L'c' || InputString[0] == L'C') && (InputString[1] == L'd' || InputString[1] == L'D')) &&\r
400 (ShellIsDirectory (FileInfo->FullName) != EFI_SUCCESS))) {\r
401 TempFileInfo = FileInfo;\r
402 FileInfo = (EFI_SHELL_FILE_INFO *) RemoveEntryList (&FileInfo->Link);\r
403 InternalFreeShellFileInfoNode (TempFileInfo);\r
404 } else {\r
405 FileInfo = (EFI_SHELL_FILE_INFO *) GetNextNode (&FileList->Link, &FileInfo->Link);\r
406 }\r
407 }\r
408 }\r
409\r
410 if (FileList != NULL && !IsListEmpty (&FileList->Link)) {\r
411 Status = EFI_SUCCESS;\r
412 } else {\r
413 ShellInfoObject.NewEfiShellProtocol->FreeFileList (&FileList);\r
414 Status = EFI_NOT_FOUND;\r
415 }\r
416\r
417 FreePool (TabStr);\r
418\r
419 *TabCompletionList = FileList;\r
420 return Status;\r
421}\r
422\r
a405b86d 423/**\r
424 File style interface for console (Read).\r
425\r
426 This will return a single line of input from the console.\r
427\r
428 @param This A pointer to the EFI_FILE_PROTOCOL instance that is the\r
429 file handle to read data from. Not used.\r
430 @param BufferSize On input, the size of the Buffer. On output, the amount\r
431 of data returned in Buffer. In both cases, the size is\r
432 measured in bytes.\r
433 @param Buffer The buffer into which the data is read.\r
434\r
435\r
436 @retval EFI_SUCCESS The data was read.\r
437 @retval EFI_NO_MEDIA The device has no medium.\r
438 @retval EFI_DEVICE_ERROR The device reported an error.\r
439 @retval EFI_DEVICE_ERROR An attempt was made to read from a deleted file.\r
440 @retval EFI_DEVICE_ERROR On entry, the current file position is beyond the end of the file.\r
441 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
442 @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to read the current directory\r
443 entry. BufferSize has been updated with the size\r
444 needed to complete the request.\r
445 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.\r
446**/\r
447EFI_STATUS\r
448EFIAPI\r
449FileInterfaceStdInRead(\r
450 IN EFI_FILE_PROTOCOL *This,\r
451 IN OUT UINTN *BufferSize,\r
452 OUT VOID *Buffer\r
453 )\r
454{\r
455 CHAR16 *CurrentString;\r
456 BOOLEAN Done;\r
9fcfa150 457 UINTN TabUpdatePos; // Start index of the string updated by TAB stroke\r
a405b86d 458 UINTN Column; // Column of current cursor\r
459 UINTN Row; // Row of current cursor\r
460 UINTN StartColumn; // Column at the beginning of the line\r
461 UINTN Update; // Line index for update\r
462 UINTN Delete; // Num of chars to delete from console after update\r
463 UINTN StringLen; // Total length of the line\r
464 UINTN StringCurPos; // Line index corresponding to the cursor\r
465 UINTN MaxStr; // Maximum possible line length\r
a405b86d 466 UINTN TotalColumn; // Num of columns in the console\r
467 UINTN TotalRow; // Num of rows in the console\r
468 UINTN SkipLength;\r
469 UINTN OutputLength; // Length of the update string\r
470 UINTN TailRow; // Row of end of line\r
471 UINTN TailColumn; // Column of end of line\r
472 EFI_INPUT_KEY Key;\r
473\r
474 BUFFER_LIST *LinePos;\r
475 BUFFER_LIST *NewPos;\r
476 BOOLEAN InScrolling;\r
477 EFI_STATUS Status;\r
478 BOOLEAN InTabScrolling; // Whether in TAB-completion state\r
9fcfa150
RN
479 EFI_SHELL_FILE_INFO *TabCompleteList;\r
480 EFI_SHELL_FILE_INFO *TabCurrent;\r
a405b86d 481 UINTN EventIndex;\r
9fcfa150 482 CHAR16 *TabOutputStr;\r
a405b86d 483\r
484 //\r
485 // If buffer is not large enough to hold a CHAR16, return minimum buffer size\r
486 //\r
487 if (*BufferSize < sizeof (CHAR16) * 2) {\r
488 *BufferSize = sizeof (CHAR16) * 2;\r
489 return (EFI_BUFFER_TOO_SMALL);\r
490 }\r
491\r
492 Done = FALSE;\r
493 CurrentString = Buffer;\r
494 StringLen = 0;\r
495 StringCurPos = 0;\r
496 OutputLength = 0;\r
497 Update = 0;\r
498 Delete = 0;\r
499 LinePos = NewPos = (BUFFER_LIST*)(&ShellInfoObject.ViewingSettings.CommandHistory);\r
500 InScrolling = FALSE;\r
501 InTabScrolling = FALSE;\r
502 Status = EFI_SUCCESS;\r
9fcfa150 503 TabOutputStr = NULL;\r
a405b86d 504 TabUpdatePos = 0;\r
9fcfa150
RN
505 TabCompleteList = NULL;\r
506 TabCurrent = NULL;\r
a405b86d 507\r
508 //\r
509 // Get the screen setting and the current cursor location\r
510 //\r
511 Column = StartColumn = gST->ConOut->Mode->CursorColumn;\r
512 Row = gST->ConOut->Mode->CursorRow;\r
513 gST->ConOut->QueryMode (gST->ConOut, gST->ConOut->Mode->Mode, &TotalColumn, &TotalRow);\r
514\r
515 //\r
516 // Limit the line length to the buffer size or the minimun size of the\r
517 // screen. (The smaller takes effect)\r
518 //\r
519 MaxStr = TotalColumn * (TotalRow - 1) - StartColumn;\r
520 if (MaxStr > *BufferSize / sizeof (CHAR16)) {\r
521 MaxStr = *BufferSize / sizeof (CHAR16);\r
522 }\r
523 ZeroMem (CurrentString, MaxStr * sizeof (CHAR16));\r
524 do {\r
525 //\r
526 // Read a key\r
527 //\r
528 gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &EventIndex);\r
529 Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
530 if (EFI_ERROR (Status)) {\r
b8f3601d
PL
531\r
532 if (Status == EFI_NOT_READY)\r
533 continue;\r
534\r
535 ZeroMem (CurrentString, MaxStr * sizeof(CHAR16));\r
536 StringLen = 0;\r
4dd8c7af 537 break;\r
a405b86d 538 }\r
539\r
540 //\r
541 // Press PageUp or PageDown to scroll the history screen up or down.\r
542 // Press any other key to quit scrolling.\r
543 //\r
544 if (Key.UnicodeChar == 0 && (Key.ScanCode == SCAN_PAGE_UP || Key.ScanCode == SCAN_PAGE_DOWN)) {\r
545 if (Key.ScanCode == SCAN_PAGE_UP) {\r
546 ConsoleLoggerDisplayHistory(FALSE, 0, ShellInfoObject.ConsoleInfo);\r
547 } else if (Key.ScanCode == SCAN_PAGE_DOWN) {\r
548 ConsoleLoggerDisplayHistory(TRUE, 0, ShellInfoObject.ConsoleInfo);\r
549 }\r
550\r
551 InScrolling = TRUE;\r
552 } else {\r
553 if (InScrolling) {\r
554 ConsoleLoggerStopHistory(ShellInfoObject.ConsoleInfo);\r
555 InScrolling = FALSE;\r
556 }\r
557 }\r
558\r
559 //\r
560 // If we are quitting TAB scrolling...\r
561 //\r
562 if (InTabScrolling && Key.UnicodeChar != CHAR_TAB) {\r
9fcfa150
RN
563 if (TabCompleteList != NULL) {\r
564 ShellInfoObject.NewEfiShellProtocol->FreeFileList (&TabCompleteList);\r
565 DEBUG_CODE(TabCompleteList = NULL;);\r
566 }\r
567 InTabScrolling = FALSE;\r
a405b86d 568 }\r
569\r
570 switch (Key.UnicodeChar) {\r
571 case CHAR_CARRIAGE_RETURN:\r
572 //\r
573 // All done, print a newline at the end of the string\r
574 //\r
575 TailRow = Row + (StringLen - StringCurPos + Column) / TotalColumn;\r
576 TailColumn = (StringLen - StringCurPos + Column) % TotalColumn;\r
577 ShellPrintEx ((INT32)TailColumn, (INT32)TailRow, L"%N\n");\r
578 Done = TRUE;\r
579 break;\r
580\r
581 case CHAR_BACKSPACE:\r
582 if (StringCurPos != 0) {\r
583 //\r
584 // If not move back beyond string beginning, move all characters behind\r
585 // the current position one character forward\r
586 //\r
587 StringCurPos--;\r
588 Update = StringCurPos;\r
589 Delete = 1;\r
590 CopyMem (CurrentString + StringCurPos, CurrentString + StringCurPos + 1, sizeof (CHAR16) * (StringLen - StringCurPos));\r
591\r
592 //\r
593 // Adjust the current column and row\r
594 //\r
595 MoveCursorBackward (TotalColumn, &Column, &Row);\r
596 }\r
597 break;\r
598\r
599 case CHAR_TAB:\r
9fcfa150
RN
600 if (!InTabScrolling) {\r
601 TabCurrent = NULL;\r
602 //\r
603 // Initialize a tab complete operation.\r
604 //\r
605 Status = CreateTabCompletionList (CurrentString, StringLen, *BufferSize, &TabCompleteList, &TabUpdatePos);\r
606 if (!EFI_ERROR(Status)) {\r
607 InTabScrolling = TRUE;\r
a405b86d 608 }\r
9fcfa150
RN
609\r
610 //\r
611 // We do not set up the replacement.\r
612 // The next section will do that.\r
613 //\r
614 }\r
615\r
616 if (InTabScrolling) {\r
617 //\r
618 // We are in a tab complete operation.\r
619 // set up the next replacement.\r
620 //\r
621 ASSERT(TabCompleteList != NULL);\r
622 if (TabCurrent == NULL) {\r
623 TabCurrent = (EFI_SHELL_FILE_INFO*) GetFirstNode (&TabCompleteList->Link);\r
a405b86d 624 } else {\r
9fcfa150 625 TabCurrent = (EFI_SHELL_FILE_INFO*) GetNextNode (&TabCompleteList->Link, &TabCurrent->Link);\r
a405b86d 626 }\r
9fcfa150
RN
627\r
628 //\r
629 // Skip over the empty list beginning node\r
630 //\r
631 if (IsNull(&TabCompleteList->Link, &TabCurrent->Link)) {\r
632 TabCurrent = (EFI_SHELL_FILE_INFO*) GetNextNode (&TabCompleteList->Link, &TabCurrent->Link);\r
a405b86d 633 }\r
634 }\r
635 break;\r
636\r
637 default:\r
638 if (Key.UnicodeChar >= ' ') {\r
639 //\r
640 // If we are at the buffer's end, drop the key\r
641 //\r
642 if (StringLen == MaxStr - 1 && (ShellInfoObject.ViewingSettings.InsertMode || StringCurPos == StringLen)) {\r
643 break;\r
644 }\r
645 //\r
646 // If in insert mode, make space by moving each other character 1\r
647 // space higher in the array\r
648 //\r
649 if (ShellInfoObject.ViewingSettings.InsertMode) {\r
650 CopyMem(CurrentString + StringCurPos + 1, CurrentString + StringCurPos, (StringLen - StringCurPos)*sizeof(CurrentString[0]));\r
651 }\r
652\r
653 CurrentString[StringCurPos] = Key.UnicodeChar;\r
654 Update = StringCurPos;\r
655\r
656 StringCurPos += 1;\r
657 OutputLength = 1;\r
658 }\r
659 break;\r
660\r
661 case 0:\r
662 switch (Key.ScanCode) {\r
663 case SCAN_DELETE:\r
664 //\r
665 // Move characters behind current position one character forward\r
666 //\r
667 if (StringLen != 0) {\r
668 Update = StringCurPos;\r
669 Delete = 1;\r
670 CopyMem (CurrentString + StringCurPos, CurrentString + StringCurPos + 1, sizeof (CHAR16) * (StringLen - StringCurPos));\r
671 }\r
672 break;\r
673\r
674 case SCAN_UP:\r
675 //\r
676 // Prepare to print the previous command\r
677 //\r
678 NewPos = (BUFFER_LIST*)GetPreviousNode(&ShellInfoObject.ViewingSettings.CommandHistory.Link, &LinePos->Link);\r
679 if (IsNull(&ShellInfoObject.ViewingSettings.CommandHistory.Link, &LinePos->Link)) {\r
680 NewPos = (BUFFER_LIST*)GetPreviousNode(&ShellInfoObject.ViewingSettings.CommandHistory.Link, &LinePos->Link);\r
681 }\r
682 break;\r
683\r
684 case SCAN_DOWN:\r
685 //\r
686 // Prepare to print the next command\r
687 //\r
688 NewPos = (BUFFER_LIST*)GetNextNode(&ShellInfoObject.ViewingSettings.CommandHistory.Link, &LinePos->Link);\r
689 if (NewPos == (BUFFER_LIST*)(&ShellInfoObject.ViewingSettings.CommandHistory)) {\r
690 NewPos = (BUFFER_LIST*)GetNextNode(&ShellInfoObject.ViewingSettings.CommandHistory.Link, &LinePos->Link);\r
691 }\r
692 break;\r
693\r
694 case SCAN_LEFT:\r
695 //\r
696 // Adjust current cursor position\r
697 //\r
698 if (StringCurPos != 0) {\r
699 --StringCurPos;\r
700 MoveCursorBackward (TotalColumn, &Column, &Row);\r
701 }\r
702 break;\r
703\r
704 case SCAN_RIGHT:\r
705 //\r
706 // Adjust current cursor position\r
707 //\r
708 if (StringCurPos < StringLen) {\r
709 ++StringCurPos;\r
710 MoveCursorForward (TotalColumn, TotalRow, &Column, &Row);\r
711 }\r
712 break;\r
713\r
714 case SCAN_HOME:\r
715 //\r
716 // Move current cursor position to the beginning of the command line\r
717 //\r
718 Row -= (StringCurPos + StartColumn) / TotalColumn;\r
719 Column = StartColumn;\r
720 StringCurPos = 0;\r
721 break;\r
722\r
723 case SCAN_END:\r
724 //\r
725 // Move current cursor position to the end of the command line\r
726 //\r
727 TailRow = Row + (StringLen - StringCurPos + Column) / TotalColumn;\r
728 TailColumn = (StringLen - StringCurPos + Column) % TotalColumn;\r
729 Row = TailRow;\r
730 Column = TailColumn;\r
731 StringCurPos = StringLen;\r
732 break;\r
733\r
734 case SCAN_ESC:\r
735 //\r
736 // Prepare to clear the current command line\r
737 //\r
738 CurrentString[0] = 0;\r
739 Update = 0;\r
740 Delete = StringLen;\r
741 Row -= (StringCurPos + StartColumn) / TotalColumn;\r
742 Column = StartColumn;\r
743 OutputLength = 0;\r
744 break;\r
745\r
746 case SCAN_INSERT:\r
747 //\r
748 // Toggle the SEnvInsertMode flag\r
749 //\r
750 ShellInfoObject.ViewingSettings.InsertMode = (BOOLEAN)!ShellInfoObject.ViewingSettings.InsertMode;\r
751 break;\r
752\r
753 case SCAN_F7:\r
754 //\r
755 // Print command history\r
756 //\r
757 PrintCommandHistory (TotalColumn, TotalRow, 4);\r
758 *CurrentString = CHAR_NULL;\r
759 Done = TRUE;\r
760 break;\r
761 }\r
762 }\r
763\r
764 if (Done) {\r
765 break;\r
766 }\r
767\r
768 //\r
769 // If we are in auto-complete mode, we are preparing to print\r
770 // the next file or directory name\r
771 //\r
772 if (InTabScrolling) {\r
9fcfa150
RN
773 TabOutputStr = AllocateZeroPool (*BufferSize);\r
774 if (TabOutputStr == NULL) {\r
775 Status = EFI_OUT_OF_RESOURCES;\r
776 }\r
777 }\r
778\r
779 if (InTabScrolling && TabOutputStr != NULL) {\r
780\r
a405b86d 781 //\r
782 // Adjust the column and row to the start of TAB-completion string.\r
783 //\r
784 Column = (StartColumn + TabUpdatePos) % TotalColumn;\r
785 Row -= (StartColumn + StringCurPos) / TotalColumn - (StartColumn + TabUpdatePos) / TotalColumn;\r
9fcfa150 786 OutputLength = StrLen (TabCurrent->FileName);\r
a405b86d 787 //\r
788 // if the output string contains blank space, quotation marks L'\"'\r
789 // should be added to the output.\r
790 //\r
9fcfa150 791 if (StrStr(TabCurrent->FileName, L" ") != NULL){\r
a405b86d 792 TabOutputStr[0] = L'\"';\r
9fcfa150 793 CopyMem (TabOutputStr + 1, TabCurrent->FileName, OutputLength * sizeof (CHAR16));\r
a405b86d 794 TabOutputStr[OutputLength + 1] = L'\"';\r
795 TabOutputStr[OutputLength + 2] = CHAR_NULL;\r
796 } else {\r
9fcfa150 797 CopyMem (TabOutputStr, TabCurrent->FileName, OutputLength * sizeof (CHAR16));\r
a405b86d 798 TabOutputStr[OutputLength] = CHAR_NULL;\r
799 }\r
800 OutputLength = StrLen (TabOutputStr) < MaxStr - 1 ? StrLen (TabOutputStr) : MaxStr - 1;\r
801 CopyMem (CurrentString + TabUpdatePos, TabOutputStr, OutputLength * sizeof (CHAR16));\r
802 CurrentString[TabUpdatePos + OutputLength] = CHAR_NULL;\r
803 StringCurPos = TabUpdatePos + OutputLength;\r
804 Update = TabUpdatePos;\r
805 if (StringLen > TabUpdatePos + OutputLength) {\r
806 Delete = StringLen - TabUpdatePos - OutputLength;\r
807 }\r
9fcfa150
RN
808\r
809 FreePool(TabOutputStr);\r
a405b86d 810 }\r
811\r
812 //\r
813 // If we have a new position, we are preparing to print a previous or\r
814 // next command.\r
815 //\r
816 if (NewPos != (BUFFER_LIST*)(&ShellInfoObject.ViewingSettings.CommandHistory)) {\r
817 Column = StartColumn;\r
818 Row -= (StringCurPos + StartColumn) / TotalColumn;\r
819\r
820 LinePos = NewPos;\r
821 NewPos = (BUFFER_LIST*)(&ShellInfoObject.ViewingSettings.CommandHistory);\r
822\r
823 OutputLength = StrLen (LinePos->Buffer) < MaxStr - 1 ? StrLen (LinePos->Buffer) : MaxStr - 1;\r
824 CopyMem (CurrentString, LinePos->Buffer, OutputLength * sizeof (CHAR16));\r
825 CurrentString[OutputLength] = CHAR_NULL;\r
826\r
827 StringCurPos = OutputLength;\r
828\r
829 //\r
830 // Draw new input string\r
831 //\r
832 Update = 0;\r
833 if (StringLen > OutputLength) {\r
834 //\r
835 // If old string was longer, blank its tail\r
836 //\r
837 Delete = StringLen - OutputLength;\r
838 }\r
839 }\r
840 //\r
841 // If we need to update the output do so now\r
842 //\r
843 if (Update != (UINTN) -1) {\r
844 ShellPrintEx ((INT32)Column, (INT32)Row, L"%s%.*s", CurrentString + Update, Delete, L"");\r
845 StringLen = StrLen (CurrentString);\r
846\r
847 if (Delete != 0) {\r
848 SetMem (CurrentString + StringLen, Delete * sizeof (CHAR16), CHAR_NULL);\r
849 }\r
850\r
851 if (StringCurPos > StringLen) {\r
852 StringCurPos = StringLen;\r
853 }\r
854\r
855 Update = (UINTN) -1;\r
856\r
857 //\r
858 // After using print to reflect newly updates, if we're not using\r
859 // BACKSPACE and DELETE, we need to move the cursor position forward,\r
860 // so adjust row and column here.\r
861 //\r
862 if (Key.UnicodeChar != CHAR_BACKSPACE && !(Key.UnicodeChar == 0 && Key.ScanCode == SCAN_DELETE)) {\r
863 //\r
864 // Calulate row and column of the tail of current string\r
865 //\r
866 TailRow = Row + (StringLen - StringCurPos + Column + OutputLength) / TotalColumn;\r
867 TailColumn = (StringLen - StringCurPos + Column + OutputLength) % TotalColumn;\r
868\r
869 //\r
870 // If the tail of string reaches screen end, screen rolls up, so if\r
871 // Row does not equal TailRow, Row should be decremented\r
872 //\r
873 // (if we are recalling commands using UPPER and DOWN key, and if the\r
874 // old command is too long to fit the screen, TailColumn must be 79.\r
875 //\r
876 if (TailColumn == 0 && TailRow >= TotalRow && Row != TailRow) {\r
877 Row--;\r
878 }\r
879 //\r
880 // Calculate the cursor position after current operation. If cursor\r
881 // reaches line end, update both row and column, otherwise, only\r
882 // column will be changed.\r
883 //\r
884 if (Column + OutputLength >= TotalColumn) {\r
885 SkipLength = OutputLength - (TotalColumn - Column);\r
886\r
887 Row += SkipLength / TotalColumn + 1;\r
888 if (Row > TotalRow - 1) {\r
889 Row = TotalRow - 1;\r
890 }\r
891\r
892 Column = SkipLength % TotalColumn;\r
893 } else {\r
894 Column += OutputLength;\r
895 }\r
896 }\r
897\r
898 Delete = 0;\r
899 }\r
900 //\r
901 // Set the cursor position for this key\r
902 //\r
903 gST->ConOut->SetCursorPosition (gST->ConOut, Column, Row);\r
904 } while (!Done);\r
905\r
906 if (CurrentString != NULL && StrLen(CurrentString) > 0) {\r
907 //\r
908 // add the line to the history buffer\r
909 //\r
910 AddLineToCommandHistory(CurrentString);\r
911 }\r
912\r
a405b86d 913 //\r
914 // Return the data to the caller\r
915 //\r
916 *BufferSize = StringLen * sizeof (CHAR16);\r
917\r
918 //\r
919 // if this was used it should be deallocated by now...\r
920 // prevent memory leaks...\r
921 //\r
9fcfa150
RN
922 if (TabCompleteList != NULL) {\r
923 ShellInfoObject.NewEfiShellProtocol->FreeFileList (&TabCompleteList);\r
9c17810a 924 }\r
9fcfa150 925 ASSERT(TabCompleteList == NULL);\r
a405b86d 926\r
4dd8c7af 927 return Status;\r
a405b86d 928}\r
929\r
930//\r
931// FILE sytle interfaces for StdIn/StdOut/StdErr\r
932//\r
933EFI_FILE_PROTOCOL FileInterfaceStdIn = {\r
934 EFI_FILE_REVISION,\r
935 FileInterfaceOpenNotFound,\r
936 FileInterfaceNopGeneric,\r
937 FileInterfaceNopGeneric,\r
938 FileInterfaceStdInRead,\r
939 FileInterfaceStdInWrite,\r
940 FileInterfaceNopGetPosition,\r
941 FileInterfaceNopSetPosition,\r
942 FileInterfaceNopGetInfo,\r
943 FileInterfaceNopSetInfo,\r
944 FileInterfaceNopGeneric\r
945};\r
946\r
947EFI_FILE_PROTOCOL FileInterfaceStdOut = {\r
948 EFI_FILE_REVISION,\r
949 FileInterfaceOpenNotFound,\r
950 FileInterfaceNopGeneric,\r
951 FileInterfaceNopGeneric,\r
952 FileInterfaceStdOutRead,\r
953 FileInterfaceStdOutWrite,\r
954 FileInterfaceNopGetPosition,\r
955 FileInterfaceNopSetPosition,\r
956 FileInterfaceNopGetInfo,\r
957 FileInterfaceNopSetInfo,\r
958 FileInterfaceNopGeneric\r
959};\r
960\r
961EFI_FILE_PROTOCOL FileInterfaceStdErr = {\r
962 EFI_FILE_REVISION,\r
963 FileInterfaceOpenNotFound,\r
964 FileInterfaceNopGeneric,\r
965 FileInterfaceNopGeneric,\r
966 FileInterfaceStdErrRead,\r
967 FileInterfaceStdErrWrite,\r
968 FileInterfaceNopGetPosition,\r
969 FileInterfaceNopSetPosition,\r
970 FileInterfaceNopGetInfo,\r
971 FileInterfaceNopSetInfo,\r
972 FileInterfaceNopGeneric\r
973};\r
974\r
975EFI_FILE_PROTOCOL FileInterfaceNulFile = {\r
976 EFI_FILE_REVISION,\r
977 FileInterfaceOpenNotFound,\r
978 FileInterfaceNopGeneric,\r
979 FileInterfaceNopGeneric,\r
980 FileInterfaceNulRead,\r
981 FileInterfaceNulWrite,\r
982 FileInterfaceNopGetPosition,\r
983 FileInterfaceNopSetPosition,\r
984 FileInterfaceNopGetInfo,\r
985 FileInterfaceNopSetInfo,\r
986 FileInterfaceNopGeneric\r
987};\r
988\r
989\r
990\r
991\r
992//\r
993// This is identical to EFI_FILE_PROTOCOL except for the additional member\r
994// for the name.\r
995//\r
996\r
997typedef struct {\r
998 UINT64 Revision;\r
999 EFI_FILE_OPEN Open;\r
1000 EFI_FILE_CLOSE Close;\r
1001 EFI_FILE_DELETE Delete;\r
1002 EFI_FILE_READ Read;\r
1003 EFI_FILE_WRITE Write;\r
1004 EFI_FILE_GET_POSITION GetPosition;\r
1005 EFI_FILE_SET_POSITION SetPosition;\r
1006 EFI_FILE_GET_INFO GetInfo;\r
1007 EFI_FILE_SET_INFO SetInfo;\r
1008 EFI_FILE_FLUSH Flush;\r
1009 CHAR16 Name[1];\r
1010} EFI_FILE_PROTOCOL_ENVIRONMENT;\r
1011//ANSI compliance helper to get size of the struct.\r
1012#define SIZE_OF_EFI_FILE_PROTOCOL_ENVIRONMENT EFI_FIELD_OFFSET (EFI_FILE_PROTOCOL_ENVIRONMENT, Name)\r
1013\r
1014/**\r
1015 File style interface for Environment Variable (Close).\r
1016\r
1017 Frees the memory for this object.\r
1018 \r
1019 @param[in] This The pointer to the EFI_FILE_PROTOCOL object.\r
1020 \r
1021 @retval EFI_SUCCESS\r
1022**/\r
1023EFI_STATUS\r
1024EFIAPI\r
1025FileInterfaceEnvClose(\r
1026 IN EFI_FILE_PROTOCOL *This\r
1027 )\r
1028{\r
416a423f
CP
1029 VOID* NewBuffer;\r
1030 UINTN NewSize;\r
1031 EFI_STATUS Status;\r
31e5b912 1032 BOOLEAN Volatile;\r
416a423f
CP
1033\r
1034 //\r
1035 // Most if not all UEFI commands will have an '\r\n' at the end of any output. \r
1036 // Since the output was redirected to a variable, it does not make sense to \r
1037 // keep this. So, before closing, strip the trailing '\r\n' from the variable\r
1038 // if it exists.\r
1039 //\r
1040 NewBuffer = NULL;\r
1041 NewSize = 0;\r
1042\r
31e5b912
RN
1043 Status = IsVolatileEnv (((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, &Volatile);\r
1044 if (EFI_ERROR (Status)) {\r
1045 return Status;\r
1046 }\r
1047\r
416a423f
CP
1048 Status = SHELL_GET_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, &NewSize, NewBuffer);\r
1049 if (Status == EFI_BUFFER_TOO_SMALL) {\r
1050 NewBuffer = AllocateZeroPool(NewSize + sizeof(CHAR16));\r
1051 if (NewBuffer == NULL) {\r
1052 return EFI_OUT_OF_RESOURCES;\r
1053 } \r
1054 Status = SHELL_GET_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, &NewSize, NewBuffer);\r
1055 }\r
1056 \r
03bc7c2b 1057 if (!EFI_ERROR(Status) && NewBuffer != NULL) {\r
416a423f
CP
1058 \r
1059 if (StrSize(NewBuffer) > 6)\r
1060 {\r
1061 if ((((CHAR16*)NewBuffer)[(StrSize(NewBuffer)/2) - 2] == CHAR_LINEFEED) \r
1062 && (((CHAR16*)NewBuffer)[(StrSize(NewBuffer)/2) - 3] == CHAR_CARRIAGE_RETURN)) {\r
1063 ((CHAR16*)NewBuffer)[(StrSize(NewBuffer)/2) - 3] = CHAR_NULL; \r
1064 }\r
31e5b912
RN
1065\r
1066 if (Volatile) {\r
416a423f
CP
1067 Status = SHELL_SET_ENVIRONMENT_VARIABLE_V(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, StrSize(NewBuffer), NewBuffer);\r
1068 } else {\r
1069 Status = SHELL_SET_ENVIRONMENT_VARIABLE_NV(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, StrSize(NewBuffer), NewBuffer);\r
1070 }\r
1071 }\r
1072 } \r
1073 \r
1074 SHELL_FREE_NON_NULL(NewBuffer);\r
a405b86d 1075 FreePool((EFI_FILE_PROTOCOL_ENVIRONMENT*)This);\r
416a423f 1076 return (Status);\r
a405b86d 1077}\r
1078\r
1079/**\r
1080 File style interface for Environment Variable (Delete).\r
1081 \r
1082 @param[in] This The pointer to the EFI_FILE_PROTOCOL object.\r
1083 \r
1084 @retval The return value from FileInterfaceEnvClose().\r
1085**/\r
1086EFI_STATUS\r
1087EFIAPI\r
1088FileInterfaceEnvDelete(\r
1089 IN EFI_FILE_PROTOCOL *This\r
1090 )\r
1091{\r
1092 SHELL_DELETE_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name);\r
1093 return (FileInterfaceEnvClose(This));\r
1094}\r
1095\r
1096/**\r
1097 File style interface for Environment Variable (Read).\r
1098 \r
4ff7e37b
ED
1099 @param[in] This The pointer to the EFI_FILE_PROTOCOL object.\r
1100 @param[in, out] BufferSize Size in bytes of Buffer.\r
1101 @param[out] Buffer The pointer to the buffer to fill.\r
a405b86d 1102 \r
1103 @retval EFI_SUCCESS The data was read.\r
1104**/\r
1105EFI_STATUS\r
1106EFIAPI\r
1107FileInterfaceEnvRead(\r
1108 IN EFI_FILE_PROTOCOL *This,\r
1109 IN OUT UINTN *BufferSize,\r
1110 OUT VOID *Buffer\r
1111 )\r
1112{\r
1113 return (SHELL_GET_ENVIRONMENT_VARIABLE(\r
1114 ((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name,\r
1115 BufferSize,\r
1116 Buffer));\r
1117}\r
1118\r
1119/**\r
1120 File style interface for Volatile Environment Variable (Write).\r
1121 \r
4ff7e37b
ED
1122 @param[in] This The pointer to the EFI_FILE_PROTOCOL object.\r
1123 @param[in, out] BufferSize Size in bytes of Buffer.\r
1124 @param[in] Buffer The pointer to the buffer to write.\r
a405b86d 1125 \r
1126 @retval EFI_SUCCESS The data was read.\r
1127**/\r
1128EFI_STATUS\r
1129EFIAPI\r
1130FileInterfaceEnvVolWrite(\r
1131 IN EFI_FILE_PROTOCOL *This,\r
1132 IN OUT UINTN *BufferSize,\r
1133 IN VOID *Buffer\r
1134 )\r
1135{\r
1136 VOID* NewBuffer;\r
1137 UINTN NewSize;\r
1138 EFI_STATUS Status;\r
1139\r
1140 NewBuffer = NULL;\r
1141 NewSize = 0;\r
1142\r
1143 Status = SHELL_GET_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, &NewSize, NewBuffer);\r
1144 if (Status == EFI_BUFFER_TOO_SMALL){\r
1145 NewBuffer = AllocateZeroPool(NewSize + *BufferSize + sizeof(CHAR16));\r
1146 Status = SHELL_GET_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, &NewSize, NewBuffer);\r
1147 }\r
1148 if (!EFI_ERROR(Status) && NewBuffer != NULL) {\r
1149 while (((CHAR16*)NewBuffer)[NewSize/2] == CHAR_NULL) {\r
1150 //\r
1151 // We want to overwrite the CHAR_NULL\r
1152 //\r
1153 NewSize -= 2;\r
1154 }\r
1155 CopyMem((UINT8*)NewBuffer + NewSize + 2, Buffer, *BufferSize);\r
1156 Status = SHELL_SET_ENVIRONMENT_VARIABLE_V(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, StrSize(NewBuffer), NewBuffer);\r
1157 FreePool(NewBuffer);\r
1158 return (Status);\r
1159 } else {\r
1160 SHELL_FREE_NON_NULL(NewBuffer);\r
1161 return (SHELL_SET_ENVIRONMENT_VARIABLE_V(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, *BufferSize, Buffer));\r
1162 }\r
1163}\r
1164\r
1165\r
1166/**\r
1167 File style interface for Non Volatile Environment Variable (Write).\r
1168 \r
4ff7e37b
ED
1169 @param[in] This The pointer to the EFI_FILE_PROTOCOL object.\r
1170 @param[in, out] BufferSize Size in bytes of Buffer.\r
1171 @param[in] Buffer The pointer to the buffer to write.\r
a405b86d 1172 \r
1173 @retval EFI_SUCCESS The data was read.\r
1174**/\r
1175EFI_STATUS\r
1176EFIAPI\r
1177FileInterfaceEnvNonVolWrite(\r
1178 IN EFI_FILE_PROTOCOL *This,\r
1179 IN OUT UINTN *BufferSize,\r
1180 IN VOID *Buffer\r
1181 )\r
1182{\r
1183 VOID* NewBuffer;\r
1184 UINTN NewSize;\r
1185 EFI_STATUS Status;\r
1186\r
1187 NewBuffer = NULL;\r
1188 NewSize = 0;\r
1189\r
1190 Status = SHELL_GET_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, &NewSize, NewBuffer);\r
1191 if (Status == EFI_BUFFER_TOO_SMALL){\r
1192 NewBuffer = AllocateZeroPool(NewSize + *BufferSize);\r
1193 Status = SHELL_GET_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, &NewSize, NewBuffer);\r
1194 }\r
1195 if (!EFI_ERROR(Status)) {\r
1196 CopyMem((UINT8*)NewBuffer + NewSize, Buffer, *BufferSize);\r
1197 return (SHELL_SET_ENVIRONMENT_VARIABLE_NV(\r
1198 ((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name,\r
1199 NewSize + *BufferSize,\r
1200 NewBuffer));\r
1201 } else {\r
1202 return (SHELL_SET_ENVIRONMENT_VARIABLE_NV(\r
1203 ((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name,\r
1204 *BufferSize,\r
1205 Buffer));\r
1206 }\r
1207}\r
1208\r
1209/**\r
1210 Creates a EFI_FILE_PROTOCOL (almost) object for using to access\r
1211 environment variables through file operations.\r
1212\r
1213 @param EnvName The name of the Environment Variable to be operated on.\r
1214\r
1215 @retval NULL Memory could not be allocated.\r
1216 @return other a pointer to an EFI_FILE_PROTOCOL structure\r
1217**/\r
1218EFI_FILE_PROTOCOL*\r
1219EFIAPI\r
1220CreateFileInterfaceEnv(\r
1221 IN CONST CHAR16 *EnvName\r
1222 )\r
1223{\r
31e5b912 1224 EFI_STATUS Status;\r
a405b86d 1225 EFI_FILE_PROTOCOL_ENVIRONMENT *EnvFileInterface;\r
323d3d11 1226 UINTN EnvNameSize;\r
31e5b912 1227 BOOLEAN Volatile;\r
a405b86d 1228\r
1229 if (EnvName == NULL) {\r
1230 return (NULL);\r
1231 }\r
1232\r
31e5b912
RN
1233 Status = IsVolatileEnv (EnvName, &Volatile);\r
1234 if (EFI_ERROR (Status)) {\r
1235 return NULL;\r
1236 }\r
1237\r
a405b86d 1238 //\r
1239 // Get some memory\r
1240 //\r
323d3d11
QS
1241 EnvNameSize = StrSize(EnvName);\r
1242 EnvFileInterface = AllocateZeroPool(sizeof(EFI_FILE_PROTOCOL_ENVIRONMENT)+EnvNameSize);\r
a405b86d 1243 if (EnvFileInterface == NULL){\r
1244 return (NULL);\r
1245 }\r
1246\r
1247 //\r
1248 // Assign the generic members\r
1249 //\r
1250 EnvFileInterface->Revision = EFI_FILE_REVISION;\r
1251 EnvFileInterface->Open = FileInterfaceOpenNotFound;\r
1252 EnvFileInterface->Close = FileInterfaceEnvClose;\r
1253 EnvFileInterface->GetPosition = FileInterfaceNopGetPosition;\r
1254 EnvFileInterface->SetPosition = FileInterfaceNopSetPosition;\r
1255 EnvFileInterface->GetInfo = FileInterfaceNopGetInfo;\r
1256 EnvFileInterface->SetInfo = FileInterfaceNopSetInfo;\r
1257 EnvFileInterface->Flush = FileInterfaceNopGeneric;\r
1258 EnvFileInterface->Delete = FileInterfaceEnvDelete;\r
1259 EnvFileInterface->Read = FileInterfaceEnvRead;\r
323d3d11
QS
1260 \r
1261 CopyMem(EnvFileInterface->Name, EnvName, EnvNameSize);\r
a405b86d 1262\r
1263 //\r
1264 // Assign the different members for Volatile and Non-Volatile variables\r
1265 //\r
31e5b912 1266 if (Volatile) {\r
a405b86d 1267 EnvFileInterface->Write = FileInterfaceEnvVolWrite;\r
1268 } else {\r
1269 EnvFileInterface->Write = FileInterfaceEnvNonVolWrite;\r
1270 }\r
1271 return ((EFI_FILE_PROTOCOL *)EnvFileInterface);\r
1272}\r
1273\r
1274/**\r
1275 Move the cursor position one character backward.\r
1276\r
1277 @param[in] LineLength Length of a line. Get it by calling QueryMode\r
4ff7e37b
ED
1278 @param[in, out] Column Current column of the cursor position\r
1279 @param[in, out] Row Current row of the cursor position\r
a405b86d 1280**/\r
1281VOID\r
1282EFIAPI\r
1283MoveCursorBackward (\r
1284 IN UINTN LineLength,\r
1285 IN OUT UINTN *Column,\r
1286 IN OUT UINTN *Row\r
1287 )\r
1288{\r
1289 //\r
1290 // If current column is 0, move to the last column of the previous line,\r
1291 // otherwise, just decrement column.\r
1292 //\r
1293 if (*Column == 0) {\r
1294 *Column = LineLength - 1;\r
1295 if (*Row > 0) {\r
1296 (*Row)--;\r
1297 }\r
1298 return;\r
1299 }\r
1300 (*Column)--;\r
1301}\r
1302\r
1303/**\r
1304 Move the cursor position one character forward.\r
1305\r
1306 @param[in] LineLength Length of a line.\r
1307 @param[in] TotalRow Total row of a screen\r
4ff7e37b
ED
1308 @param[in, out] Column Current column of the cursor position\r
1309 @param[in, out] Row Current row of the cursor position\r
a405b86d 1310**/\r
1311VOID\r
1312EFIAPI\r
1313MoveCursorForward (\r
1314 IN UINTN LineLength,\r
1315 IN UINTN TotalRow,\r
1316 IN OUT UINTN *Column,\r
1317 IN OUT UINTN *Row\r
1318 )\r
1319{\r
1320 //\r
1321 // Increment Column.\r
1322 // If this puts column past the end of the line, move to first column\r
1323 // of the next row.\r
1324 //\r
1325 (*Column)++;\r
1326 if (*Column >= LineLength) {\r
1327 (*Column) = 0;\r
1328 if ((*Row) < TotalRow - 1) {\r
1329 (*Row)++;\r
1330 }\r
1331 }\r
1332}\r
1333\r
1334/**\r
1335 Prints out each previously typed command in the command list history log.\r
1336\r
1337 When each screen is full it will pause for a key before continuing.\r
1338\r
1339 @param[in] TotalCols How many columns are on the screen\r
1340 @param[in] TotalRows How many rows are on the screen\r
1341 @param[in] StartColumn which column to start at\r
1342**/\r
1343VOID\r
1344EFIAPI\r
1345PrintCommandHistory (\r
1346 IN CONST UINTN TotalCols,\r
1347 IN CONST UINTN TotalRows,\r
1348 IN CONST UINTN StartColumn\r
1349 )\r
1350{\r
1351 BUFFER_LIST *Node;\r
1352 UINTN Index;\r
1353 UINTN LineNumber;\r
1354 UINTN LineCount;\r
1355\r
1356 ShellPrintEx (-1, -1, L"\n");\r
1357 Index = 0;\r
1358 LineNumber = 0;\r
1359 //\r
1360 // go through history list...\r
1361 //\r
1362 for ( Node = (BUFFER_LIST*)GetFirstNode(&ShellInfoObject.ViewingSettings.CommandHistory.Link)\r
1363 ; !IsNull(&ShellInfoObject.ViewingSettings.CommandHistory.Link, &Node->Link)\r
1364 ; Node = (BUFFER_LIST*)GetNextNode(&ShellInfoObject.ViewingSettings.CommandHistory.Link, &Node->Link)\r
1365 ){\r
1366 Index++;\r
1367 LineCount = ((StrLen (Node->Buffer) + StartColumn + 1) / TotalCols) + 1;\r
1368\r
1369 if (LineNumber + LineCount >= TotalRows) {\r
1370 ShellPromptForResponseHii(\r
1371 ShellPromptResponseTypeEnterContinue,\r
1372 STRING_TOKEN (STR_SHELL_ENTER_TO_CONT),\r
1373 ShellInfoObject.HiiHandle,\r
1374 NULL\r
1375 );\r
1376 LineNumber = 0;\r
1377 }\r
1378 ShellPrintEx (-1, -1, L"%2d. %s\n", Index, Node->Buffer);\r
1379 LineNumber += LineCount;\r
1380 }\r
1381}\r
1382\r
1383\r
1384\r
1385\r
1386\r
1387\r
1388//\r
1389// This is identical to EFI_FILE_PROTOCOL except for the additional members\r
1390// for the buffer, size, and position.\r
1391//\r
1392\r
1393typedef struct {\r
1394 UINT64 Revision;\r
1395 EFI_FILE_OPEN Open;\r
1396 EFI_FILE_CLOSE Close;\r
1397 EFI_FILE_DELETE Delete;\r
1398 EFI_FILE_READ Read;\r
1399 EFI_FILE_WRITE Write;\r
1400 EFI_FILE_GET_POSITION GetPosition;\r
1401 EFI_FILE_SET_POSITION SetPosition;\r
1402 EFI_FILE_GET_INFO GetInfo;\r
1403 EFI_FILE_SET_INFO SetInfo;\r
1404 EFI_FILE_FLUSH Flush;\r
1405 VOID *Buffer;\r
1406 UINT64 Position;\r
1407 UINT64 BufferSize;\r
1408 BOOLEAN Unicode;\r
7bcd3ff6 1409 UINT64 FileSize;\r
a405b86d 1410} EFI_FILE_PROTOCOL_MEM;\r
1411\r
1412/**\r
1413 File style interface for Mem (SetPosition).\r
1414 \r
1415 @param[in] This The pointer to the EFI_FILE_PROTOCOL object.\r
1416 @param[out] Position The position to set.\r
1417 \r
1418 @retval EFI_SUCCESS The position was successfully changed.\r
1419 @retval EFI_INVALID_PARAMETER The Position was invalid.\r
1420**/\r
1421EFI_STATUS\r
1422EFIAPI\r
1423FileInterfaceMemSetPosition(\r
1424 IN EFI_FILE_PROTOCOL *This,\r
1425 OUT UINT64 Position\r
1426 )\r
1427{\r
7bcd3ff6 1428 if (Position <= ((EFI_FILE_PROTOCOL_MEM*)This)->FileSize) {\r
a405b86d 1429 ((EFI_FILE_PROTOCOL_MEM*)This)->Position = Position;\r
1430 return (EFI_SUCCESS);\r
1431 } else {\r
1432 return (EFI_INVALID_PARAMETER);\r
1433 }\r
1434}\r
1435\r
1436/**\r
1437 File style interface for Mem (GetPosition).\r
1438 \r
1439 @param[in] This The pointer to the EFI_FILE_PROTOCOL object.\r
1440 @param[out] Position The pointer to the position.\r
1441 \r
1442 @retval EFI_SUCCESS The position was retrieved.\r
1443**/ \r
1444EFI_STATUS\r
1445EFIAPI\r
1446FileInterfaceMemGetPosition(\r
1447 IN EFI_FILE_PROTOCOL *This,\r
1448 OUT UINT64 *Position\r
1449 )\r
1450{\r
1451 *Position = ((EFI_FILE_PROTOCOL_MEM*)This)->Position;\r
1452 return (EFI_SUCCESS);\r
1453}\r
1454\r
1455/**\r
1456 File style interface for Mem (Write).\r
1457 \r
4ff7e37b
ED
1458 @param[in] This The pointer to the EFI_FILE_PROTOCOL object.\r
1459 @param[in, out] BufferSize Size in bytes of Buffer.\r
1460 @param[in] Buffer The pointer to the buffer to write.\r
a405b86d 1461 \r
ecae5117 1462 @retval EFI_OUT_OF_RESOURCES The operation failed due to lack of resources.\r
1463 @retval EFI_SUCCESS The data was written.\r
a405b86d 1464**/\r
1465EFI_STATUS\r
1466EFIAPI\r
1467FileInterfaceMemWrite(\r
1468 IN EFI_FILE_PROTOCOL *This,\r
1469 IN OUT UINTN *BufferSize,\r
1470 IN VOID *Buffer\r
1471 )\r
1472{\r
9ed21946 1473 CHAR8 *AsciiBuffer;\r
1474 EFI_FILE_PROTOCOL_MEM *MemFile;\r
1475\r
1476 MemFile = (EFI_FILE_PROTOCOL_MEM *) This;\r
1477 if (MemFile->Unicode) {\r
a405b86d 1478 //\r
1479 // Unicode\r
1480 //\r
9ed21946 1481 if ((UINTN)(MemFile->Position + (*BufferSize)) > (UINTN)(MemFile->BufferSize)) {\r
c8d9d0e2
JD
1482 MemFile->Buffer = ReallocatePool((UINTN)(MemFile->BufferSize), (UINTN)(MemFile->BufferSize) + (*BufferSize) + MEM_WRITE_REALLOC_OVERHEAD, MemFile->Buffer);\r
1483 MemFile->BufferSize += (*BufferSize) + MEM_WRITE_REALLOC_OVERHEAD;\r
a405b86d 1484 }\r
9ed21946 1485 CopyMem(((UINT8*)MemFile->Buffer) + MemFile->Position, Buffer, *BufferSize);\r
1486 MemFile->Position += (*BufferSize);\r
7bcd3ff6 1487 MemFile->FileSize = MemFile->Position;\r
a405b86d 1488 return (EFI_SUCCESS);\r
1489 } else {\r
1490 //\r
1491 // Ascii\r
1492 //\r
733f138d 1493 AsciiBuffer = AllocateZeroPool(*BufferSize);\r
ecae5117 1494 if (AsciiBuffer == NULL) {\r
1495 return (EFI_OUT_OF_RESOURCES);\r
1496 }\r
a405b86d 1497 AsciiSPrint(AsciiBuffer, *BufferSize, "%S", Buffer);\r
9ed21946 1498 if ((UINTN)(MemFile->Position + AsciiStrSize(AsciiBuffer)) > (UINTN)(MemFile->BufferSize)) {\r
c8d9d0e2
JD
1499 MemFile->Buffer = ReallocatePool((UINTN)(MemFile->BufferSize), (UINTN)(MemFile->BufferSize) + AsciiStrSize(AsciiBuffer) + MEM_WRITE_REALLOC_OVERHEAD, MemFile->Buffer);\r
1500 MemFile->BufferSize += AsciiStrSize(AsciiBuffer) + MEM_WRITE_REALLOC_OVERHEAD;\r
a405b86d 1501 }\r
9ed21946 1502 CopyMem(((UINT8*)MemFile->Buffer) + MemFile->Position, AsciiBuffer, AsciiStrSize(AsciiBuffer));\r
1503 MemFile->Position += (*BufferSize / sizeof(CHAR16));\r
7bcd3ff6 1504 MemFile->FileSize = MemFile->Position;\r
a405b86d 1505 FreePool(AsciiBuffer);\r
1506 return (EFI_SUCCESS);\r
1507 }\r
1508}\r
1509\r
1510/**\r
1511 File style interface for Mem (Read).\r
1512 \r
4ff7e37b
ED
1513 @param[in] This The pointer to the EFI_FILE_PROTOCOL object.\r
1514 @param[in, out] BufferSize Size in bytes of Buffer.\r
1515 @param[in] Buffer The pointer to the buffer to fill.\r
a405b86d 1516 \r
1517 @retval EFI_SUCCESS The data was read.\r
1518**/\r
1519EFI_STATUS\r
1520EFIAPI\r
1521FileInterfaceMemRead(\r
1522 IN EFI_FILE_PROTOCOL *This,\r
1523 IN OUT UINTN *BufferSize,\r
1524 IN VOID *Buffer\r
1525 )\r
1526{\r
9ed21946 1527 EFI_FILE_PROTOCOL_MEM *MemFile;\r
1528\r
1529 MemFile = (EFI_FILE_PROTOCOL_MEM *) This;\r
7bcd3ff6
JD
1530 if (*BufferSize > (UINTN)((MemFile->FileSize) - (UINTN)(MemFile->Position))) {\r
1531 (*BufferSize) = (UINTN)((MemFile->FileSize) - (UINTN)(MemFile->Position));\r
a405b86d 1532 }\r
9ed21946 1533 CopyMem(Buffer, ((UINT8*)MemFile->Buffer) + MemFile->Position, (*BufferSize));\r
1534 MemFile->Position = MemFile->Position + (*BufferSize);\r
a405b86d 1535 return (EFI_SUCCESS);\r
1536}\r
1537\r
1538/**\r
1539 File style interface for Mem (Close).\r
1540\r
1541 Frees all memory associated with this object.\r
1542 \r
1543 @param[in] This The pointer to the EFI_FILE_PROTOCOL object.\r
1544 \r
1545 @retval EFI_SUCCESS The 'file' was closed.\r
1546**/ \r
1547EFI_STATUS\r
1548EFIAPI\r
1549FileInterfaceMemClose(\r
1550 IN EFI_FILE_PROTOCOL *This\r
1551 )\r
1552{\r
1553 SHELL_FREE_NON_NULL(((EFI_FILE_PROTOCOL_MEM*)This)->Buffer);\r
3c865f20 1554 SHELL_FREE_NON_NULL(This);\r
a405b86d 1555 return (EFI_SUCCESS);\r
1556}\r
1557\r
1558/**\r
1559 Creates a EFI_FILE_PROTOCOL (almost) object for using to access\r
1560 a file entirely in memory through file operations.\r
1561\r
1562 @param[in] Unicode Boolean value with TRUE for Unicode and FALSE for Ascii.\r
1563\r
1564 @retval NULL Memory could not be allocated.\r
1565 @return other A pointer to an EFI_FILE_PROTOCOL structure.\r
1566**/\r
1567EFI_FILE_PROTOCOL*\r
1568EFIAPI\r
1569CreateFileInterfaceMem(\r
1570 IN CONST BOOLEAN Unicode\r
1571 )\r
1572{\r
1573 EFI_FILE_PROTOCOL_MEM *FileInterface;\r
1574\r
1575 //\r
1576 // Get some memory\r
1577 //\r
1578 FileInterface = AllocateZeroPool(sizeof(EFI_FILE_PROTOCOL_MEM));\r
1579 if (FileInterface == NULL){\r
1580 return (NULL);\r
1581 }\r
1582\r
1583 //\r
1584 // Assign the generic members\r
1585 //\r
1586 FileInterface->Revision = EFI_FILE_REVISION;\r
1587 FileInterface->Open = FileInterfaceOpenNotFound;\r
1588 FileInterface->Close = FileInterfaceMemClose;\r
1589 FileInterface->GetPosition = FileInterfaceMemGetPosition;\r
1590 FileInterface->SetPosition = FileInterfaceMemSetPosition;\r
1591 FileInterface->GetInfo = FileInterfaceNopGetInfo;\r
1592 FileInterface->SetInfo = FileInterfaceNopSetInfo;\r
1593 FileInterface->Flush = FileInterfaceNopGeneric;\r
1594 FileInterface->Delete = FileInterfaceNopGeneric;\r
1595 FileInterface->Read = FileInterfaceMemRead;\r
1596 FileInterface->Write = FileInterfaceMemWrite;\r
1597 FileInterface->Unicode = Unicode;\r
1598\r
1599 ASSERT(FileInterface->Buffer == NULL);\r
1600 ASSERT(FileInterface->BufferSize == 0);\r
1601 ASSERT(FileInterface->Position == 0);\r
1602\r
9ed21946 1603 if (Unicode) {\r
1604 FileInterface->Buffer = AllocateZeroPool(sizeof(gUnicodeFileTag));\r
9eec4d38
QS
1605 if (FileInterface->Buffer == NULL) {\r
1606 FreePool (FileInterface);\r
1607 return NULL;\r
1608 }\r
9ed21946 1609 *((CHAR16 *) (FileInterface->Buffer)) = EFI_UNICODE_BYTE_ORDER_MARK;\r
1610 FileInterface->BufferSize = 2;\r
1611 FileInterface->Position = 2;\r
1612 }\r
1613\r
a405b86d 1614 return ((EFI_FILE_PROTOCOL *)FileInterface);\r
1615}\r
1616\r
1617typedef struct {\r
1618 UINT64 Revision;\r
1619 EFI_FILE_OPEN Open;\r
1620 EFI_FILE_CLOSE Close;\r
1621 EFI_FILE_DELETE Delete;\r
1622 EFI_FILE_READ Read;\r
1623 EFI_FILE_WRITE Write;\r
1624 EFI_FILE_GET_POSITION GetPosition;\r
1625 EFI_FILE_SET_POSITION SetPosition;\r
1626 EFI_FILE_GET_INFO GetInfo;\r
1627 EFI_FILE_SET_INFO SetInfo;\r
1628 EFI_FILE_FLUSH Flush;\r
1629 BOOLEAN Unicode;\r
1630 EFI_FILE_PROTOCOL *Orig;\r
1631} EFI_FILE_PROTOCOL_FILE;\r
1632\r
733f138d 1633/**\r
1634 Set a files current position\r
1635\r
1636 @param This Protocol instance pointer.\r
1637 @param Position Byte position from the start of the file.\r
1638 \r
1639 @retval EFI_SUCCESS Data was written.\r
1640 @retval EFI_UNSUPPORTED Seek request for non-zero is not valid on open.\r
1641\r
1642**/\r
1643EFI_STATUS\r
1644EFIAPI\r
1645FileInterfaceFileSetPosition(\r
1646 IN EFI_FILE_PROTOCOL *This,\r
1647 IN UINT64 Position\r
1648 )\r
1649{\r
1650 return ((EFI_FILE_PROTOCOL_FILE*)This)->Orig->SetPosition(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, Position);\r
1651}\r
1652\r
1653/**\r
1654 Get a file's current position\r
1655\r
1656 @param This Protocol instance pointer.\r
1657 @param Position Byte position from the start of the file.\r
1658 \r
1659 @retval EFI_SUCCESS Data was written.\r
1660 @retval EFI_UNSUPPORTED Seek request for non-zero is not valid on open..\r
1661\r
1662**/\r
1663EFI_STATUS\r
1664EFIAPI\r
1665FileInterfaceFileGetPosition(\r
1666 IN EFI_FILE_PROTOCOL *This,\r
1667 OUT UINT64 *Position\r
1668 )\r
1669{\r
1670 return ((EFI_FILE_PROTOCOL_FILE*)This)->Orig->GetPosition(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, Position);\r
1671}\r
1672\r
1673/**\r
1674 Get information about a file.\r
1675\r
1676 @param This Protocol instance pointer.\r
1677 @param InformationType Type of information to return in Buffer.\r
1678 @param BufferSize On input size of buffer, on output amount of data in buffer.\r
1679 @param Buffer The buffer to return data.\r
1680\r
1681 @retval EFI_SUCCESS Data was returned.\r
1682 @retval EFI_UNSUPPORT InformationType is not supported.\r
1683 @retval EFI_NO_MEDIA The device has no media.\r
1684 @retval EFI_DEVICE_ERROR The device reported an error.\r
1685 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
1686 @retval EFI_WRITE_PROTECTED The device is write protected.\r
1687 @retval EFI_ACCESS_DENIED The file was open for read only.\r
1688 @retval EFI_BUFFER_TOO_SMALL Buffer was too small; required size returned in BufferSize.\r
1689\r
1690**/\r
1691EFI_STATUS\r
1692EFIAPI\r
1693FileInterfaceFileGetInfo(\r
1694 IN EFI_FILE_PROTOCOL *This,\r
1695 IN EFI_GUID *InformationType,\r
1696 IN OUT UINTN *BufferSize,\r
1697 OUT VOID *Buffer\r
1698 )\r
1699{\r
1700 return ((EFI_FILE_PROTOCOL_FILE*)This)->Orig->GetInfo(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, InformationType, BufferSize, Buffer);\r
1701}\r
1702\r
1703/**\r
1704 Set information about a file\r
1705\r
ae724571 1706 @param This Protocol instance pointer.\r
733f138d 1707 @param InformationType Type of information in Buffer.\r
1708 @param BufferSize Size of buffer.\r
1709 @param Buffer The data to write.\r
1710\r
1711 @retval EFI_SUCCESS Data was returned.\r
1712 @retval EFI_UNSUPPORT InformationType is not supported.\r
1713 @retval EFI_NO_MEDIA The device has no media.\r
1714 @retval EFI_DEVICE_ERROR The device reported an error.\r
1715 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
1716 @retval EFI_WRITE_PROTECTED The device is write protected.\r
1717 @retval EFI_ACCESS_DENIED The file was open for read only.\r
1718\r
1719**/\r
1720EFI_STATUS\r
1721EFIAPI\r
1722FileInterfaceFileSetInfo(\r
1723 IN EFI_FILE_PROTOCOL *This,\r
1724 IN EFI_GUID *InformationType,\r
1725 IN UINTN BufferSize,\r
1726 IN VOID *Buffer\r
1727 )\r
1728{\r
1729 return ((EFI_FILE_PROTOCOL_FILE*)This)->Orig->SetInfo(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, InformationType, BufferSize, Buffer);\r
1730}\r
1731\r
1732/**\r
1733 Flush data back for the file handle.\r
1734\r
1735 @param This Protocol instance pointer.\r
1736\r
1737 @retval EFI_SUCCESS Data was written.\r
1738 @retval EFI_UNSUPPORT Writes to Open directory are not supported.\r
1739 @retval EFI_NO_MEDIA The device has no media.\r
1740 @retval EFI_DEVICE_ERROR The device reported an error.\r
1741 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
1742 @retval EFI_WRITE_PROTECTED The device is write protected.\r
1743 @retval EFI_ACCESS_DENIED The file was open for read only.\r
1744 @retval EFI_VOLUME_FULL The volume is full.\r
1745\r
1746**/\r
1747EFI_STATUS\r
1748EFIAPI\r
1749FileInterfaceFileFlush(\r
1750 IN EFI_FILE_PROTOCOL *This\r
1751 )\r
1752{\r
1753 return ((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Flush(((EFI_FILE_PROTOCOL_FILE*)This)->Orig);\r
1754}\r
1755\r
1756/**\r
1757 Read data from the file.\r
1758\r
1759 @param This Protocol instance pointer.\r
1760 @param BufferSize On input size of buffer, on output amount of data in buffer.\r
1761 @param Buffer The buffer in which data is read.\r
1762\r
1763 @retval EFI_SUCCESS Data was read.\r
1764 @retval EFI_NO_MEDIA The device has no media.\r
1765 @retval EFI_DEVICE_ERROR The device reported an error.\r
1766 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
1767 @retval EFI_BUFFER_TO_SMALL BufferSize is too small. BufferSize contains required size.\r
1768\r
1769**/\r
1770EFI_STATUS\r
1771EFIAPI\r
1772FileInterfaceFileRead(\r
1773 IN EFI_FILE_PROTOCOL *This,\r
1774 IN OUT UINTN *BufferSize,\r
1775 OUT VOID *Buffer\r
1776 )\r
1777{\r
48cb33ec
QS
1778 CHAR8 *AsciiStrBuffer;\r
1779 CHAR16 *UscStrBuffer;\r
733f138d 1780 UINTN Size;\r
48cb33ec 1781 UINTN CharNum;\r
733f138d 1782 EFI_STATUS Status;\r
1783 if (((EFI_FILE_PROTOCOL_FILE*)This)->Unicode) {\r
1784 //\r
1785 // Unicode\r
1786 //\r
1787 return (((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Read(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, BufferSize, Buffer));\r
1788 } else {\r
1789 //\r
1790 // Ascii\r
1791 //\r
48cb33ec
QS
1792 Size = (*BufferSize) / sizeof(CHAR16);\r
1793 AsciiStrBuffer = AllocateZeroPool(Size + sizeof(CHAR8));\r
1794 if (AsciiStrBuffer == NULL) {\r
1795 return EFI_OUT_OF_RESOURCES;\r
1796 }\r
1797 UscStrBuffer = AllocateZeroPool(*BufferSize + sizeof(CHAR16));\r
1798 if (UscStrBuffer== NULL) {\r
1799 SHELL_FREE_NON_NULL(AsciiStrBuffer);\r
1800 return EFI_OUT_OF_RESOURCES;\r
1801 }\r
1802 Status = (((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Read(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, &Size, AsciiStrBuffer));\r
1803 if (!EFI_ERROR(Status)) {\r
1804 CharNum = UnicodeSPrint(UscStrBuffer, *BufferSize + sizeof(CHAR16), L"%a", AsciiStrBuffer);\r
1805 if (CharNum == Size) {\r
1806 CopyMem (Buffer, UscStrBuffer, *BufferSize);\r
1807 } else {\r
1808 Status = EFI_UNSUPPORTED;\r
1809 }\r
1810 }\r
1811 SHELL_FREE_NON_NULL(AsciiStrBuffer);\r
1812 SHELL_FREE_NON_NULL(UscStrBuffer);\r
733f138d 1813 return (Status);\r
1814 }\r
1815}\r
1816\r
1817/**\r
1818 Opens a new file relative to the source file's location.\r
1819\r
1820 @param[in] This The protocol instance pointer.\r
1821 @param[out] NewHandle Returns File Handle for FileName.\r
1822 @param[in] FileName Null terminated string. "\", ".", and ".." are supported.\r
1823 @param[in] OpenMode Open mode for file.\r
1824 @param[in] Attributes Only used for EFI_FILE_MODE_CREATE.\r
1825\r
1826 @retval EFI_SUCCESS The device was opened.\r
1827 @retval EFI_NOT_FOUND The specified file could not be found on the device.\r
1828 @retval EFI_NO_MEDIA The device has no media.\r
1829 @retval EFI_MEDIA_CHANGED The media has changed.\r
1830 @retval EFI_DEVICE_ERROR The device reported an error.\r
1831 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
1832 @retval EFI_ACCESS_DENIED The service denied access to the file.\r
1833 @retval EFI_OUT_OF_RESOURCES The volume was not opened due to lack of resources.\r
1834 @retval EFI_VOLUME_FULL The volume is full.\r
1835**/\r
1836EFI_STATUS\r
1837EFIAPI\r
1838FileInterfaceFileOpen (\r
1839 IN EFI_FILE_PROTOCOL *This,\r
1840 OUT EFI_FILE_PROTOCOL **NewHandle,\r
1841 IN CHAR16 *FileName,\r
1842 IN UINT64 OpenMode,\r
1843 IN UINT64 Attributes\r
1844 )\r
1845{\r
1846 return ((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Open(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, NewHandle, FileName, OpenMode, Attributes);\r
1847}\r
1848\r
1849/**\r
1850 Close and delete the file handle.\r
1851\r
1852 @param This Protocol instance pointer.\r
1853 \r
1854 @retval EFI_SUCCESS The device was opened.\r
1855 @retval EFI_WARN_DELETE_FAILURE The handle was closed but the file was not deleted.\r
1856\r
1857**/\r
1858EFI_STATUS\r
1859EFIAPI\r
1860FileInterfaceFileDelete(\r
1861 IN EFI_FILE_PROTOCOL *This\r
1862 )\r
1863{\r
1864 EFI_STATUS Status;\r
1865 Status = ((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Delete(((EFI_FILE_PROTOCOL_FILE*)This)->Orig);\r
1866 FreePool(This);\r
1867 return (Status);\r
1868}\r
1869\r
a405b86d 1870/**\r
1871 File style interface for File (Close).\r
1872 \r
1873 @param[in] This The pointer to the EFI_FILE_PROTOCOL object.\r
1874 \r
1875 @retval EFI_SUCCESS The file was closed.\r
1876**/\r
1877EFI_STATUS\r
1878EFIAPI\r
1879FileInterfaceFileClose(\r
1880 IN EFI_FILE_PROTOCOL *This\r
1881 )\r
1882{\r
733f138d 1883 EFI_STATUS Status;\r
1884 Status = ((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Close(((EFI_FILE_PROTOCOL_FILE*)This)->Orig);\r
a405b86d 1885 FreePool(This);\r
733f138d 1886 return (Status);\r
a405b86d 1887}\r
1888\r
1889/**\r
1890 File style interface for File (Write).\r
1891\r
1892 If the file was opened with ASCII mode the data will be processed through \r
1893 AsciiSPrint before writing.\r
1894 \r
4ff7e37b
ED
1895 @param[in] This The pointer to the EFI_FILE_PROTOCOL object.\r
1896 @param[in, out] BufferSize Size in bytes of Buffer.\r
1897 @param[in] Buffer The pointer to the buffer to write.\r
a405b86d 1898 \r
1899 @retval EFI_SUCCESS The data was written.\r
1900**/\r
1901EFI_STATUS\r
1902EFIAPI\r
1903FileInterfaceFileWrite(\r
733f138d 1904 IN EFI_FILE_PROTOCOL *This,\r
1905 IN OUT UINTN *BufferSize,\r
1906 IN VOID *Buffer\r
a405b86d 1907 )\r
1908{\r
1909 CHAR8 *AsciiBuffer;\r
1910 UINTN Size;\r
1911 EFI_STATUS Status;\r
1912 if (((EFI_FILE_PROTOCOL_FILE*)This)->Unicode) {\r
1913 //\r
1914 // Unicode\r
1915 //\r
1916 return (((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Write(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, BufferSize, Buffer));\r
1917 } else {\r
1918 //\r
1919 // Ascii\r
1920 //\r
733f138d 1921 AsciiBuffer = AllocateZeroPool(*BufferSize);\r
a405b86d 1922 AsciiSPrint(AsciiBuffer, *BufferSize, "%S", Buffer);\r
1923 Size = AsciiStrSize(AsciiBuffer) - 1; // (we dont need the null terminator)\r
1924 Status = (((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Write(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, &Size, AsciiBuffer));\r
1925 FreePool(AsciiBuffer);\r
1926 return (Status);\r
1927 }\r
1928}\r
1929\r
1930/**\r
1931 Create a file interface with unicode information.\r
1932\r
1933 This will create a new EFI_FILE_PROTOCOL identical to the Templace\r
1934 except that the new one has Unicode and Ascii knowledge.\r
1935 \r
1936 @param[in] Template A pointer to the EFI_FILE_PROTOCOL object.\r
1937 @param[in] Unicode TRUE for UCS-2, FALSE for ASCII.\r
1938 \r
1939 @return a new EFI_FILE_PROTOCOL object to be used instead of the template.\r
1940**/\r
1941EFI_FILE_PROTOCOL*\r
1942CreateFileInterfaceFile(\r
1943 IN CONST EFI_FILE_PROTOCOL *Template,\r
1944 IN CONST BOOLEAN Unicode\r
1945 )\r
1946{\r
1947 EFI_FILE_PROTOCOL_FILE *NewOne;\r
1948\r
733f138d 1949 NewOne = AllocateZeroPool(sizeof(EFI_FILE_PROTOCOL_FILE));\r
3c865f20 1950 if (NewOne == NULL) {\r
1951 return (NULL);\r
1952 }\r
a405b86d 1953 CopyMem(NewOne, Template, sizeof(EFI_FILE_PROTOCOL_FILE));\r
733f138d 1954 NewOne->Orig = (EFI_FILE_PROTOCOL *)Template;\r
1955 NewOne->Unicode = Unicode;\r
1956 NewOne->Open = FileInterfaceFileOpen;\r
1957 NewOne->Close = FileInterfaceFileClose;\r
1958 NewOne->Delete = FileInterfaceFileDelete;\r
1959 NewOne->Read = FileInterfaceFileRead;\r
1960 NewOne->Write = FileInterfaceFileWrite;\r
1961 NewOne->GetPosition = FileInterfaceFileGetPosition;\r
1962 NewOne->SetPosition = FileInterfaceFileSetPosition;\r
1963 NewOne->GetInfo = FileInterfaceFileGetInfo;\r
1964 NewOne->SetInfo = FileInterfaceFileSetInfo;\r
1965 NewOne->Flush = FileInterfaceFileFlush;\r
a405b86d 1966\r
1967 return ((EFI_FILE_PROTOCOL *)NewOne);\r
1968}\r