blob: 4b53c7080c306f9e69335f2b4a0c8c63b2aaa060 [file] [log] [blame]
jcarsey94b17fa2009-05-07 18:46:18 +00001/** @file
2 Provides interface to shell functionality for shell commands and applications.
3
jaben carsey9ed21942016-02-08 15:59:04 -08004 Copyright 2016 Dell Inc.
jaben carsey21a86a72015-01-13 22:16:41 +00005 Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
jcarsey1e6e84c2010-01-25 20:05:08 +00006 This program and the accompanying materials
jcarseyb3011f42010-01-11 21:49:04 +00007 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
jcarsey94b17fa2009-05-07 18:46:18 +000010
jcarseyb3011f42010-01-11 21:49:04 +000011 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
jcarsey94b17fa2009-05-07 18:46:18 +000013
14**/
15
jcarseyb1f95a02009-06-16 00:23:19 +000016#include "UefiShellLib.h"
jcarseya405b862010-09-14 05:18:09 +000017#include <ShellBase.h>
jcarsey252d9452011-03-25 20:49:53 +000018#include <Library/SortLib.h>
Laszlo Ersek3fe23dc2015-01-14 16:25:48 +000019#include <Library/BaseLib.h>
jcarseyd2b45642009-05-11 18:02:16 +000020
jcarsey94b17fa2009-05-07 18:46:18 +000021#define FIND_XXXXX_FILE_BUFFER_SIZE (SIZE_OF_EFI_FILE_INFO + MAX_FILE_NAME_LEN)
22
jcarseyd2b45642009-05-11 18:02:16 +000023//
jcarseya405b862010-09-14 05:18:09 +000024// globals...
jcarseyd2b45642009-05-11 18:02:16 +000025//
26SHELL_PARAM_ITEM EmptyParamList[] = {
27 {NULL, TypeMax}
28 };
jcarseya405b862010-09-14 05:18:09 +000029SHELL_PARAM_ITEM SfoParamList[] = {
30 {L"-sfo", TypeFlag},
31 {NULL, TypeMax}
32 };
33EFI_SHELL_ENVIRONMENT2 *mEfiShellEnvironment2;
34EFI_SHELL_INTERFACE *mEfiShellInterface;
jcarsey366f81a2011-06-27 21:04:22 +000035EFI_SHELL_PROTOCOL *gEfiShellProtocol;
36EFI_SHELL_PARAMETERS_PROTOCOL *gEfiShellParametersProtocol;
jcarseya405b862010-09-14 05:18:09 +000037EFI_HANDLE mEfiShellEnvironment2Handle;
38FILE_HANDLE_FUNCTION_MAP FileFunctionMap;
jcarseyb3011f42010-01-11 21:49:04 +000039
jcarsey2247dde2009-11-09 18:08:58 +000040/**
41 Check if a Unicode character is a hexadecimal character.
42
jcarsey1e6e84c2010-01-25 20:05:08 +000043 This internal function checks if a Unicode character is a
jcarseya405b862010-09-14 05:18:09 +000044 numeric character. The valid hexadecimal characters are
jcarsey2247dde2009-11-09 18:08:58 +000045 L'0' to L'9', L'a' to L'f', or L'A' to L'F'.
46
jcarsey2247dde2009-11-09 18:08:58 +000047 @param Char The character to check against.
48
49 @retval TRUE If the Char is a hexadecmial character.
50 @retval FALSE If the Char is not a hexadecmial character.
51
52**/
53BOOLEAN
54EFIAPI
jcarsey969c7832010-01-13 16:46:33 +000055ShellIsHexaDecimalDigitCharacter (
jcarsey2247dde2009-11-09 18:08:58 +000056 IN CHAR16 Char
jcarseya405b862010-09-14 05:18:09 +000057 )
58{
jcarsey2247dde2009-11-09 18:08:58 +000059 return (BOOLEAN) ((Char >= L'0' && Char <= L'9') || (Char >= L'A' && Char <= L'F') || (Char >= L'a' && Char <= L'f'));
60}
jcarsey94b17fa2009-05-07 18:46:18 +000061
62/**
jcarseya405b862010-09-14 05:18:09 +000063 Check if a Unicode character is a decimal character.
64
65 This internal function checks if a Unicode character is a
66 decimal character. The valid characters are
67 L'0' to L'9'.
68
69
70 @param Char The character to check against.
71
72 @retval TRUE If the Char is a hexadecmial character.
73 @retval FALSE If the Char is not a hexadecmial character.
74
75**/
76BOOLEAN
77EFIAPI
78ShellIsDecimalDigitCharacter (
79 IN CHAR16 Char
80 )
81{
82 return (BOOLEAN) (Char >= L'0' && Char <= L'9');
83}
84
85/**
86 Helper function to find ShellEnvironment2 for constructor.
87
88 @param[in] ImageHandle A copy of the calling image's handle.
jcarseybeab0fc2011-10-10 17:26:25 +000089
90 @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
jcarsey94b17fa2009-05-07 18:46:18 +000091**/
92EFI_STATUS
93EFIAPI
94ShellFindSE2 (
95 IN EFI_HANDLE ImageHandle
jcarseya405b862010-09-14 05:18:09 +000096 )
97{
jcarsey94b17fa2009-05-07 18:46:18 +000098 EFI_STATUS Status;
99 EFI_HANDLE *Buffer;
100 UINTN BufferSize;
101 UINTN HandleIndex;
102
103 BufferSize = 0;
104 Buffer = NULL;
jcarsey1e6e84c2010-01-25 20:05:08 +0000105 Status = gBS->OpenProtocol(ImageHandle,
jcarsey94b17fa2009-05-07 18:46:18 +0000106 &gEfiShellEnvironment2Guid,
107 (VOID **)&mEfiShellEnvironment2,
108 ImageHandle,
109 NULL,
110 EFI_OPEN_PROTOCOL_GET_PROTOCOL
jcarseya405b862010-09-14 05:18:09 +0000111 );
jcarsey94b17fa2009-05-07 18:46:18 +0000112 //
113 // look for the mEfiShellEnvironment2 protocol at a higher level
114 //
jcarseya405b862010-09-14 05:18:09 +0000115 if (EFI_ERROR (Status) || !(CompareGuid (&mEfiShellEnvironment2->SESGuid, &gEfiShellEnvironment2ExtGuid))){
jcarsey94b17fa2009-05-07 18:46:18 +0000116 //
117 // figure out how big of a buffer we need.
118 //
119 Status = gBS->LocateHandle (ByProtocol,
120 &gEfiShellEnvironment2Guid,
121 NULL, // ignored for ByProtocol
122 &BufferSize,
123 Buffer
jcarseya405b862010-09-14 05:18:09 +0000124 );
jcarsey2247dde2009-11-09 18:08:58 +0000125 //
126 // maybe it's not there???
127 //
128 if (Status == EFI_BUFFER_TOO_SMALL) {
jcarsey252d9452011-03-25 20:49:53 +0000129 Buffer = (EFI_HANDLE*)AllocateZeroPool(BufferSize);
jcarseybeab0fc2011-10-10 17:26:25 +0000130 if (Buffer == NULL) {
131 return (EFI_OUT_OF_RESOURCES);
132 }
jcarsey2247dde2009-11-09 18:08:58 +0000133 Status = gBS->LocateHandle (ByProtocol,
134 &gEfiShellEnvironment2Guid,
135 NULL, // ignored for ByProtocol
136 &BufferSize,
137 Buffer
jcarseya405b862010-09-14 05:18:09 +0000138 );
jcarsey2247dde2009-11-09 18:08:58 +0000139 }
jcarsey1cd45e72010-01-29 15:07:44 +0000140 if (!EFI_ERROR (Status) && Buffer != NULL) {
jcarsey94b17fa2009-05-07 18:46:18 +0000141 //
142 // now parse the list of returned handles
143 //
144 Status = EFI_NOT_FOUND;
145 for (HandleIndex = 0; HandleIndex < (BufferSize/sizeof(Buffer[0])); HandleIndex++) {
jcarsey1e6e84c2010-01-25 20:05:08 +0000146 Status = gBS->OpenProtocol(Buffer[HandleIndex],
jcarsey94b17fa2009-05-07 18:46:18 +0000147 &gEfiShellEnvironment2Guid,
148 (VOID **)&mEfiShellEnvironment2,
149 ImageHandle,
150 NULL,
151 EFI_OPEN_PROTOCOL_GET_PROTOCOL
jcarseya405b862010-09-14 05:18:09 +0000152 );
153 if (CompareGuid (&mEfiShellEnvironment2->SESGuid, &gEfiShellEnvironment2ExtGuid)) {
jcarsey94b17fa2009-05-07 18:46:18 +0000154 mEfiShellEnvironment2Handle = Buffer[HandleIndex];
155 Status = EFI_SUCCESS;
156 break;
157 }
158 }
159 }
160 }
161 if (Buffer != NULL) {
162 FreePool (Buffer);
163 }
164 return (Status);
165}
166
jcarsey252d9452011-03-25 20:49:53 +0000167/**
darylm503b0934ac2011-11-12 00:35:11 +0000168 Function to do most of the work of the constructor. Allows for calling
jcarseya405b862010-09-14 05:18:09 +0000169 multiple times without complete re-initialization.
170
171 @param[in] ImageHandle A copy of the ImageHandle.
172 @param[in] SystemTable A pointer to the SystemTable for the application.
jcarsey252d9452011-03-25 20:49:53 +0000173
174 @retval EFI_SUCCESS The operationw as successful.
jcarseya405b862010-09-14 05:18:09 +0000175**/
jcarsey94b17fa2009-05-07 18:46:18 +0000176EFI_STATUS
177EFIAPI
jcarseyd2b45642009-05-11 18:02:16 +0000178ShellLibConstructorWorker (
jcarsey94b17fa2009-05-07 18:46:18 +0000179 IN EFI_HANDLE ImageHandle,
180 IN EFI_SYSTEM_TABLE *SystemTable
jcarseya405b862010-09-14 05:18:09 +0000181 )
182{
183 EFI_STATUS Status;
jcarseyecd3d592009-12-07 18:05:00 +0000184
jcarsey94b17fa2009-05-07 18:46:18 +0000185 //
186 // UEFI 2.0 shell interfaces (used preferentially)
187 //
jcarseya405b862010-09-14 05:18:09 +0000188 Status = gBS->OpenProtocol(
189 ImageHandle,
190 &gEfiShellProtocolGuid,
jcarsey366f81a2011-06-27 21:04:22 +0000191 (VOID **)&gEfiShellProtocol,
jcarseya405b862010-09-14 05:18:09 +0000192 ImageHandle,
193 NULL,
194 EFI_OPEN_PROTOCOL_GET_PROTOCOL
195 );
jcarsey94b17fa2009-05-07 18:46:18 +0000196 if (EFI_ERROR(Status)) {
jcarseya405b862010-09-14 05:18:09 +0000197 //
198 // Search for the shell protocol
199 //
200 Status = gBS->LocateProtocol(
201 &gEfiShellProtocolGuid,
202 NULL,
jcarsey366f81a2011-06-27 21:04:22 +0000203 (VOID **)&gEfiShellProtocol
jcarseya405b862010-09-14 05:18:09 +0000204 );
205 if (EFI_ERROR(Status)) {
jcarsey366f81a2011-06-27 21:04:22 +0000206 gEfiShellProtocol = NULL;
jcarseya405b862010-09-14 05:18:09 +0000207 }
jcarsey94b17fa2009-05-07 18:46:18 +0000208 }
jcarseya405b862010-09-14 05:18:09 +0000209 Status = gBS->OpenProtocol(
210 ImageHandle,
211 &gEfiShellParametersProtocolGuid,
jcarsey366f81a2011-06-27 21:04:22 +0000212 (VOID **)&gEfiShellParametersProtocol,
jcarseya405b862010-09-14 05:18:09 +0000213 ImageHandle,
214 NULL,
215 EFI_OPEN_PROTOCOL_GET_PROTOCOL
216 );
jcarsey94b17fa2009-05-07 18:46:18 +0000217 if (EFI_ERROR(Status)) {
jcarsey366f81a2011-06-27 21:04:22 +0000218 gEfiShellParametersProtocol = NULL;
jcarsey94b17fa2009-05-07 18:46:18 +0000219 }
220
jcarsey366f81a2011-06-27 21:04:22 +0000221 if (gEfiShellParametersProtocol == NULL || gEfiShellProtocol == NULL) {
jcarsey94b17fa2009-05-07 18:46:18 +0000222 //
223 // Moved to seperate function due to complexity
224 //
225 Status = ShellFindSE2(ImageHandle);
226
227 if (EFI_ERROR(Status)) {
228 DEBUG((DEBUG_ERROR, "Status: 0x%08x\r\n", Status));
229 mEfiShellEnvironment2 = NULL;
230 }
jcarsey1e6e84c2010-01-25 20:05:08 +0000231 Status = gBS->OpenProtocol(ImageHandle,
jcarsey94b17fa2009-05-07 18:46:18 +0000232 &gEfiShellInterfaceGuid,
233 (VOID **)&mEfiShellInterface,
234 ImageHandle,
235 NULL,
236 EFI_OPEN_PROTOCOL_GET_PROTOCOL
jcarseya405b862010-09-14 05:18:09 +0000237 );
jcarsey94b17fa2009-05-07 18:46:18 +0000238 if (EFI_ERROR(Status)) {
239 mEfiShellInterface = NULL;
240 }
241 }
jcarseyc9d92df2010-02-03 15:37:54 +0000242
jcarsey94b17fa2009-05-07 18:46:18 +0000243 //
244 // only success getting 2 of either the old or new, but no 1/2 and 1/2
245 //
jcarsey1e6e84c2010-01-25 20:05:08 +0000246 if ((mEfiShellEnvironment2 != NULL && mEfiShellInterface != NULL) ||
jcarsey366f81a2011-06-27 21:04:22 +0000247 (gEfiShellProtocol != NULL && gEfiShellParametersProtocol != NULL) ) {
248 if (gEfiShellProtocol != NULL) {
249 FileFunctionMap.GetFileInfo = gEfiShellProtocol->GetFileInfo;
250 FileFunctionMap.SetFileInfo = gEfiShellProtocol->SetFileInfo;
251 FileFunctionMap.ReadFile = gEfiShellProtocol->ReadFile;
252 FileFunctionMap.WriteFile = gEfiShellProtocol->WriteFile;
253 FileFunctionMap.CloseFile = gEfiShellProtocol->CloseFile;
254 FileFunctionMap.DeleteFile = gEfiShellProtocol->DeleteFile;
255 FileFunctionMap.GetFilePosition = gEfiShellProtocol->GetFilePosition;
256 FileFunctionMap.SetFilePosition = gEfiShellProtocol->SetFilePosition;
257 FileFunctionMap.FlushFile = gEfiShellProtocol->FlushFile;
258 FileFunctionMap.GetFileSize = gEfiShellProtocol->GetFileSize;
jcarseyd2b45642009-05-11 18:02:16 +0000259 } else {
jcarseya405b862010-09-14 05:18:09 +0000260 FileFunctionMap.GetFileInfo = (EFI_SHELL_GET_FILE_INFO)FileHandleGetInfo;
261 FileFunctionMap.SetFileInfo = (EFI_SHELL_SET_FILE_INFO)FileHandleSetInfo;
262 FileFunctionMap.ReadFile = (EFI_SHELL_READ_FILE)FileHandleRead;
263 FileFunctionMap.WriteFile = (EFI_SHELL_WRITE_FILE)FileHandleWrite;
264 FileFunctionMap.CloseFile = (EFI_SHELL_CLOSE_FILE)FileHandleClose;
265 FileFunctionMap.DeleteFile = (EFI_SHELL_DELETE_FILE)FileHandleDelete;
266 FileFunctionMap.GetFilePosition = (EFI_SHELL_GET_FILE_POSITION)FileHandleGetPosition;
267 FileFunctionMap.SetFilePosition = (EFI_SHELL_SET_FILE_POSITION)FileHandleSetPosition;
268 FileFunctionMap.FlushFile = (EFI_SHELL_FLUSH_FILE)FileHandleFlush;
269 FileFunctionMap.GetFileSize = (EFI_SHELL_GET_FILE_SIZE)FileHandleGetSize;
jcarseyd2b45642009-05-11 18:02:16 +0000270 }
jcarsey94b17fa2009-05-07 18:46:18 +0000271 return (EFI_SUCCESS);
272 }
273 return (EFI_NOT_FOUND);
274}
jcarseyd2b45642009-05-11 18:02:16 +0000275/**
276 Constructor for the Shell library.
277
278 Initialize the library and determine if the underlying is a UEFI Shell 2.0 or an EFI shell.
279
280 @param ImageHandle the image handle of the process
281 @param SystemTable the EFI System Table pointer
282
283 @retval EFI_SUCCESS the initialization was complete sucessfully
284 @return others an error ocurred during initialization
285**/
286EFI_STATUS
287EFIAPI
288ShellLibConstructor (
289 IN EFI_HANDLE ImageHandle,
290 IN EFI_SYSTEM_TABLE *SystemTable
jcarseya405b862010-09-14 05:18:09 +0000291 )
292{
jcarseyd2b45642009-05-11 18:02:16 +0000293 mEfiShellEnvironment2 = NULL;
jcarsey366f81a2011-06-27 21:04:22 +0000294 gEfiShellProtocol = NULL;
295 gEfiShellParametersProtocol = NULL;
jcarseyd2b45642009-05-11 18:02:16 +0000296 mEfiShellInterface = NULL;
297 mEfiShellEnvironment2Handle = NULL;
298
jcarseyd2b45642009-05-11 18:02:16 +0000299 //
300 // verify that auto initialize is not set false
jcarsey1e6e84c2010-01-25 20:05:08 +0000301 //
jcarseyd2b45642009-05-11 18:02:16 +0000302 if (PcdGetBool(PcdShellLibAutoInitialize) == 0) {
303 return (EFI_SUCCESS);
304 }
jcarsey1e6e84c2010-01-25 20:05:08 +0000305
jcarseyd2b45642009-05-11 18:02:16 +0000306 return (ShellLibConstructorWorker(ImageHandle, SystemTable));
307}
jcarsey94b17fa2009-05-07 18:46:18 +0000308
309/**
jcarseya405b862010-09-14 05:18:09 +0000310 Destructor for the library. free any resources.
311
312 @param[in] ImageHandle A copy of the ImageHandle.
313 @param[in] SystemTable A pointer to the SystemTable for the application.
314
315 @retval EFI_SUCCESS The operation was successful.
316 @return An error from the CloseProtocol function.
jcarsey94b17fa2009-05-07 18:46:18 +0000317**/
318EFI_STATUS
319EFIAPI
320ShellLibDestructor (
321 IN EFI_HANDLE ImageHandle,
322 IN EFI_SYSTEM_TABLE *SystemTable
jcarseya405b862010-09-14 05:18:09 +0000323 )
324{
jcarsey94b17fa2009-05-07 18:46:18 +0000325 if (mEfiShellEnvironment2 != NULL) {
326 gBS->CloseProtocol(mEfiShellEnvironment2Handle==NULL?ImageHandle:mEfiShellEnvironment2Handle,
327 &gEfiShellEnvironment2Guid,
328 ImageHandle,
329 NULL);
jcarseyd2b45642009-05-11 18:02:16 +0000330 mEfiShellEnvironment2 = NULL;
jcarsey94b17fa2009-05-07 18:46:18 +0000331 }
332 if (mEfiShellInterface != NULL) {
333 gBS->CloseProtocol(ImageHandle,
334 &gEfiShellInterfaceGuid,
335 ImageHandle,
jcarsey1e6e84c2010-01-25 20:05:08 +0000336 NULL);
jcarseyd2b45642009-05-11 18:02:16 +0000337 mEfiShellInterface = NULL;
jcarsey94b17fa2009-05-07 18:46:18 +0000338 }
jcarsey366f81a2011-06-27 21:04:22 +0000339 if (gEfiShellProtocol != NULL) {
jcarsey94b17fa2009-05-07 18:46:18 +0000340 gBS->CloseProtocol(ImageHandle,
341 &gEfiShellProtocolGuid,
342 ImageHandle,
jcarsey1e6e84c2010-01-25 20:05:08 +0000343 NULL);
jcarsey366f81a2011-06-27 21:04:22 +0000344 gEfiShellProtocol = NULL;
jcarsey94b17fa2009-05-07 18:46:18 +0000345 }
jcarsey366f81a2011-06-27 21:04:22 +0000346 if (gEfiShellParametersProtocol != NULL) {
jcarsey94b17fa2009-05-07 18:46:18 +0000347 gBS->CloseProtocol(ImageHandle,
348 &gEfiShellParametersProtocolGuid,
349 ImageHandle,
jcarsey1e6e84c2010-01-25 20:05:08 +0000350 NULL);
jcarsey366f81a2011-06-27 21:04:22 +0000351 gEfiShellParametersProtocol = NULL;
jcarsey94b17fa2009-05-07 18:46:18 +0000352 }
jcarseyd2b45642009-05-11 18:02:16 +0000353 mEfiShellEnvironment2Handle = NULL;
jcarseyecd3d592009-12-07 18:05:00 +0000354
jcarsey94b17fa2009-05-07 18:46:18 +0000355 return (EFI_SUCCESS);
356}
jcarseyd2b45642009-05-11 18:02:16 +0000357
358/**
359 This function causes the shell library to initialize itself. If the shell library
360 is already initialized it will de-initialize all the current protocol poitners and
361 re-populate them again.
362
363 When the library is used with PcdShellLibAutoInitialize set to true this function
364 will return EFI_SUCCESS and perform no actions.
365
366 This function is intended for internal access for shell commands only.
367
368 @retval EFI_SUCCESS the initialization was complete sucessfully
369
370**/
371EFI_STATUS
372EFIAPI
373ShellInitialize (
jcarseya405b862010-09-14 05:18:09 +0000374 )
375{
jcarseyd2b45642009-05-11 18:02:16 +0000376 //
377 // if auto initialize is not false then skip
378 //
379 if (PcdGetBool(PcdShellLibAutoInitialize) != 0) {
380 return (EFI_SUCCESS);
381 }
382
383 //
384 // deinit the current stuff
385 //
386 ASSERT_EFI_ERROR(ShellLibDestructor(gImageHandle, gST));
387
388 //
389 // init the new stuff
390 //
391 return (ShellLibConstructorWorker(gImageHandle, gST));
392}
393
jcarsey94b17fa2009-05-07 18:46:18 +0000394/**
jcarsey1e6e84c2010-01-25 20:05:08 +0000395 This function will retrieve the information about the file for the handle
jcarsey94b17fa2009-05-07 18:46:18 +0000396 specified and store it in allocated pool memory.
397
jcarsey1e6e84c2010-01-25 20:05:08 +0000398 This function allocates a buffer to store the file's information. It is the
qhuang869817bf2009-05-20 14:42:48 +0000399 caller's responsibility to free the buffer
jcarsey94b17fa2009-05-07 18:46:18 +0000400
jcarsey1e6e84c2010-01-25 20:05:08 +0000401 @param FileHandle The file handle of the file for which information is
jcarsey94b17fa2009-05-07 18:46:18 +0000402 being requested.
403
404 @retval NULL information could not be retrieved.
405
406 @return the information about the file
407**/
408EFI_FILE_INFO*
409EFIAPI
410ShellGetFileInfo (
jcarseya405b862010-09-14 05:18:09 +0000411 IN SHELL_FILE_HANDLE FileHandle
412 )
413{
jcarseyd2b45642009-05-11 18:02:16 +0000414 return (FileFunctionMap.GetFileInfo(FileHandle));
jcarsey94b17fa2009-05-07 18:46:18 +0000415}
416
417/**
jcarseya405b862010-09-14 05:18:09 +0000418 This function sets the information about the file for the opened handle
jcarsey94b17fa2009-05-07 18:46:18 +0000419 specified.
420
jcarseya405b862010-09-14 05:18:09 +0000421 @param[in] FileHandle The file handle of the file for which information
422 is being set.
jcarsey94b17fa2009-05-07 18:46:18 +0000423
jcarseya405b862010-09-14 05:18:09 +0000424 @param[in] FileInfo The information to set.
jcarsey94b17fa2009-05-07 18:46:18 +0000425
darylm503b0934ac2011-11-12 00:35:11 +0000426 @retval EFI_SUCCESS The information was set.
jcarseya405b862010-09-14 05:18:09 +0000427 @retval EFI_INVALID_PARAMETER A parameter was out of range or invalid.
428 @retval EFI_UNSUPPORTED The FileHandle does not support FileInfo.
darylm503b0934ac2011-11-12 00:35:11 +0000429 @retval EFI_NO_MEDIA The device has no medium.
430 @retval EFI_DEVICE_ERROR The device reported an error.
431 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
432 @retval EFI_WRITE_PROTECTED The file or medium is write protected.
jcarseya405b862010-09-14 05:18:09 +0000433 @retval EFI_ACCESS_DENIED The file was opened read only.
434 @retval EFI_VOLUME_FULL The volume is full.
jcarsey94b17fa2009-05-07 18:46:18 +0000435**/
436EFI_STATUS
437EFIAPI
438ShellSetFileInfo (
darylm503b0934ac2011-11-12 00:35:11 +0000439 IN SHELL_FILE_HANDLE FileHandle,
jcarsey94b17fa2009-05-07 18:46:18 +0000440 IN EFI_FILE_INFO *FileInfo
jcarseya405b862010-09-14 05:18:09 +0000441 )
442{
jcarseyd2b45642009-05-11 18:02:16 +0000443 return (FileFunctionMap.SetFileInfo(FileHandle, FileInfo));
jcarsey1e6e84c2010-01-25 20:05:08 +0000444}
445
jcarsey94b17fa2009-05-07 18:46:18 +0000446 /**
447 This function will open a file or directory referenced by DevicePath.
448
jcarsey1e6e84c2010-01-25 20:05:08 +0000449 This function opens a file with the open mode according to the file path. The
jcarsey94b17fa2009-05-07 18:46:18 +0000450 Attributes is valid only for EFI_FILE_MODE_CREATE.
451
darylm503b0934ac2011-11-12 00:35:11 +0000452 @param FilePath on input the device path to the file. On output
jcarsey94b17fa2009-05-07 18:46:18 +0000453 the remaining device path.
darylm503b0934ac2011-11-12 00:35:11 +0000454 @param DeviceHandle pointer to the system device handle.
455 @param FileHandle pointer to the file handle.
456 @param OpenMode the mode to open the file with.
457 @param Attributes the file's file attributes.
jcarsey94b17fa2009-05-07 18:46:18 +0000458
darylm503b0934ac2011-11-12 00:35:11 +0000459 @retval EFI_SUCCESS The information was set.
460 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
461 @retval EFI_UNSUPPORTED Could not open the file path.
462 @retval EFI_NOT_FOUND The specified file could not be found on the
jcarsey1e6e84c2010-01-25 20:05:08 +0000463 device or the file system could not be found on
jcarsey94b17fa2009-05-07 18:46:18 +0000464 the device.
darylm503b0934ac2011-11-12 00:35:11 +0000465 @retval EFI_NO_MEDIA The device has no medium.
466 @retval EFI_MEDIA_CHANGED The device has a different medium in it or the
jcarsey94b17fa2009-05-07 18:46:18 +0000467 medium is no longer supported.
darylm503b0934ac2011-11-12 00:35:11 +0000468 @retval EFI_DEVICE_ERROR The device reported an error.
469 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
470 @retval EFI_WRITE_PROTECTED The file or medium is write protected.
471 @retval EFI_ACCESS_DENIED The file was opened read only.
472 @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the
jcarsey94b17fa2009-05-07 18:46:18 +0000473 file.
darylm503b0934ac2011-11-12 00:35:11 +0000474 @retval EFI_VOLUME_FULL The volume is full.
jcarsey94b17fa2009-05-07 18:46:18 +0000475**/
476EFI_STATUS
477EFIAPI
478ShellOpenFileByDevicePath(
darylm503b0934ac2011-11-12 00:35:11 +0000479 IN OUT EFI_DEVICE_PATH_PROTOCOL **FilePath,
480 OUT EFI_HANDLE *DeviceHandle,
jcarseya405b862010-09-14 05:18:09 +0000481 OUT SHELL_FILE_HANDLE *FileHandle,
darylm503b0934ac2011-11-12 00:35:11 +0000482 IN UINT64 OpenMode,
483 IN UINT64 Attributes
jcarseya405b862010-09-14 05:18:09 +0000484 )
485{
486 CHAR16 *FileName;
487 EFI_STATUS Status;
jcarsey94b17fa2009-05-07 18:46:18 +0000488 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *EfiSimpleFileSystemProtocol;
jcarseya405b862010-09-14 05:18:09 +0000489 EFI_FILE_PROTOCOL *Handle1;
490 EFI_FILE_PROTOCOL *Handle2;
ydong100b6cb332013-01-25 02:00:22 +0000491 CHAR16 *FnafPathName;
492 UINTN PathLen;
jcarsey94b17fa2009-05-07 18:46:18 +0000493
jcarsey92a54472011-06-27 20:33:13 +0000494 if (FilePath == NULL || FileHandle == NULL || DeviceHandle == NULL) {
495 return (EFI_INVALID_PARAMETER);
496 }
497
jcarsey1e6e84c2010-01-25 20:05:08 +0000498 //
jcarsey94b17fa2009-05-07 18:46:18 +0000499 // which shell interface should we use
500 //
jcarsey366f81a2011-06-27 21:04:22 +0000501 if (gEfiShellProtocol != NULL) {
jcarsey94b17fa2009-05-07 18:46:18 +0000502 //
503 // use UEFI Shell 2.0 method.
504 //
jcarsey366f81a2011-06-27 21:04:22 +0000505 FileName = gEfiShellProtocol->GetFilePathFromDevicePath(*FilePath);
jcarsey94b17fa2009-05-07 18:46:18 +0000506 if (FileName == NULL) {
507 return (EFI_INVALID_PARAMETER);
508 }
509 Status = ShellOpenFileByName(FileName, FileHandle, OpenMode, Attributes);
510 FreePool(FileName);
511 return (Status);
jcarsey1e6e84c2010-01-25 20:05:08 +0000512 }
jcarseyd2b45642009-05-11 18:02:16 +0000513
514
515 //
516 // use old shell method.
517 //
jcarsey1e6e84c2010-01-25 20:05:08 +0000518 Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid,
519 FilePath,
jcarseyd2b45642009-05-11 18:02:16 +0000520 DeviceHandle);
521 if (EFI_ERROR (Status)) {
522 return Status;
523 }
524 Status = gBS->OpenProtocol(*DeviceHandle,
525 &gEfiSimpleFileSystemProtocolGuid,
jcarseyb1f95a02009-06-16 00:23:19 +0000526 (VOID**)&EfiSimpleFileSystemProtocol,
jcarseyd2b45642009-05-11 18:02:16 +0000527 gImageHandle,
528 NULL,
529 EFI_OPEN_PROTOCOL_GET_PROTOCOL);
530 if (EFI_ERROR (Status)) {
531 return Status;
532 }
jcarseya405b862010-09-14 05:18:09 +0000533 Status = EfiSimpleFileSystemProtocol->OpenVolume(EfiSimpleFileSystemProtocol, &Handle1);
jcarseyd2b45642009-05-11 18:02:16 +0000534 if (EFI_ERROR (Status)) {
535 FileHandle = NULL;
536 return Status;
537 }
538
539 //
540 // go down directories one node at a time.
541 //
542 while (!IsDevicePathEnd (*FilePath)) {
jcarsey94b17fa2009-05-07 18:46:18 +0000543 //
jcarseyd2b45642009-05-11 18:02:16 +0000544 // For file system access each node should be a file path component
jcarsey94b17fa2009-05-07 18:46:18 +0000545 //
jcarseyd2b45642009-05-11 18:02:16 +0000546 if (DevicePathType (*FilePath) != MEDIA_DEVICE_PATH ||
547 DevicePathSubType (*FilePath) != MEDIA_FILEPATH_DP
jcarseya405b862010-09-14 05:18:09 +0000548 ) {
jcarsey94b17fa2009-05-07 18:46:18 +0000549 FileHandle = NULL;
jcarseyd2b45642009-05-11 18:02:16 +0000550 return (EFI_INVALID_PARAMETER);
jcarsey94b17fa2009-05-07 18:46:18 +0000551 }
jcarseyd2b45642009-05-11 18:02:16 +0000552 //
553 // Open this file path node
554 //
jcarseya405b862010-09-14 05:18:09 +0000555 Handle2 = Handle1;
556 Handle1 = NULL;
jcarsey94b17fa2009-05-07 18:46:18 +0000557
558 //
ydong100b6cb332013-01-25 02:00:22 +0000559 // File Name Alignment Fix (FNAF)
560 // Handle2->Open may be incapable of handling a unaligned CHAR16 data.
561 // The structure pointed to by FilePath may be not CHAR16 aligned.
562 // This code copies the potentially unaligned PathName data from the
563 // FilePath structure to the aligned FnafPathName for use in the
564 // calls to Handl2->Open.
565 //
566
567 //
568 // Determine length of PathName, in bytes.
569 //
570 PathLen = DevicePathNodeLength (*FilePath) - SIZE_OF_FILEPATH_DEVICE_PATH;
571
572 //
573 // Allocate memory for the aligned copy of the string Extra allocation is to allow for forced alignment
574 // Copy bytes from possibly unaligned location to aligned location
575 //
576 FnafPathName = AllocateCopyPool(PathLen, (UINT8 *)((FILEPATH_DEVICE_PATH*)*FilePath)->PathName);
577 if (FnafPathName == NULL) {
578 return EFI_OUT_OF_RESOURCES;
579 }
580
581 //
jcarseyd2b45642009-05-11 18:02:16 +0000582 // Try to test opening an existing file
jcarsey94b17fa2009-05-07 18:46:18 +0000583 //
jcarseya405b862010-09-14 05:18:09 +0000584 Status = Handle2->Open (
585 Handle2,
586 &Handle1,
ydong100b6cb332013-01-25 02:00:22 +0000587 FnafPathName,
jcarseyd2b45642009-05-11 18:02:16 +0000588 OpenMode &~EFI_FILE_MODE_CREATE,
589 0
jcarseya405b862010-09-14 05:18:09 +0000590 );
jcarsey94b17fa2009-05-07 18:46:18 +0000591
jcarseyd2b45642009-05-11 18:02:16 +0000592 //
593 // see if the error was that it needs to be created
594 //
595 if ((EFI_ERROR (Status)) && (OpenMode != (OpenMode &~EFI_FILE_MODE_CREATE))) {
jcarseya405b862010-09-14 05:18:09 +0000596 Status = Handle2->Open (
597 Handle2,
598 &Handle1,
ydong100b6cb332013-01-25 02:00:22 +0000599 FnafPathName,
jcarseyd2b45642009-05-11 18:02:16 +0000600 OpenMode,
601 Attributes
jcarseya405b862010-09-14 05:18:09 +0000602 );
jcarsey94b17fa2009-05-07 18:46:18 +0000603 }
ydong100b6cb332013-01-25 02:00:22 +0000604
605 //
606 // Free the alignment buffer
607 //
608 FreePool(FnafPathName);
609
jcarseyd2b45642009-05-11 18:02:16 +0000610 //
611 // Close the last node
612 //
jcarseya405b862010-09-14 05:18:09 +0000613 Handle2->Close (Handle2);
jcarseyd2b45642009-05-11 18:02:16 +0000614
615 if (EFI_ERROR(Status)) {
616 return (Status);
617 }
618
619 //
620 // Get the next node
621 //
622 *FilePath = NextDevicePathNode (*FilePath);
jcarsey94b17fa2009-05-07 18:46:18 +0000623 }
jcarseya405b862010-09-14 05:18:09 +0000624
625 //
626 // This is a weak spot since if the undefined SHELL_FILE_HANDLE format changes this must change also!
627 //
628 *FileHandle = (VOID*)Handle1;
jcarseyd2b45642009-05-11 18:02:16 +0000629 return (EFI_SUCCESS);
jcarsey94b17fa2009-05-07 18:46:18 +0000630}
631
632/**
633 This function will open a file or directory referenced by filename.
634
jcarsey1e6e84c2010-01-25 20:05:08 +0000635 If return is EFI_SUCCESS, the Filehandle is the opened file's handle;
636 otherwise, the Filehandle is NULL. The Attributes is valid only for
jcarsey94b17fa2009-05-07 18:46:18 +0000637 EFI_FILE_MODE_CREATE.
638
jcarsey92a54472011-06-27 20:33:13 +0000639 if FileName is NULL then ASSERT()
jcarsey94b17fa2009-05-07 18:46:18 +0000640
darylm503b0934ac2011-11-12 00:35:11 +0000641 @param FileName pointer to file name
642 @param FileHandle pointer to the file handle.
643 @param OpenMode the mode to open the file with.
644 @param Attributes the file's file attributes.
jcarsey94b17fa2009-05-07 18:46:18 +0000645
darylm503b0934ac2011-11-12 00:35:11 +0000646 @retval EFI_SUCCESS The information was set.
647 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
648 @retval EFI_UNSUPPORTED Could not open the file path.
649 @retval EFI_NOT_FOUND The specified file could not be found on the
jcarsey1e6e84c2010-01-25 20:05:08 +0000650 device or the file system could not be found
jcarsey94b17fa2009-05-07 18:46:18 +0000651 on the device.
darylm503b0934ac2011-11-12 00:35:11 +0000652 @retval EFI_NO_MEDIA The device has no medium.
653 @retval EFI_MEDIA_CHANGED The device has a different medium in it or the
jcarsey94b17fa2009-05-07 18:46:18 +0000654 medium is no longer supported.
darylm503b0934ac2011-11-12 00:35:11 +0000655 @retval EFI_DEVICE_ERROR The device reported an error.
656 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
657 @retval EFI_WRITE_PROTECTED The file or medium is write protected.
658 @retval EFI_ACCESS_DENIED The file was opened read only.
659 @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the
jcarsey94b17fa2009-05-07 18:46:18 +0000660 file.
darylm503b0934ac2011-11-12 00:35:11 +0000661 @retval EFI_VOLUME_FULL The volume is full.
jcarsey94b17fa2009-05-07 18:46:18 +0000662**/
663EFI_STATUS
664EFIAPI
665ShellOpenFileByName(
darylm503b0934ac2011-11-12 00:35:11 +0000666 IN CONST CHAR16 *FileName,
jcarseya405b862010-09-14 05:18:09 +0000667 OUT SHELL_FILE_HANDLE *FileHandle,
jcarsey94b17fa2009-05-07 18:46:18 +0000668 IN UINT64 OpenMode,
darylm503b0934ac2011-11-12 00:35:11 +0000669 IN UINT64 Attributes
jcarseya405b862010-09-14 05:18:09 +0000670 )
671{
jcarsey94b17fa2009-05-07 18:46:18 +0000672 EFI_HANDLE DeviceHandle;
673 EFI_DEVICE_PATH_PROTOCOL *FilePath;
jcarseyb1f95a02009-06-16 00:23:19 +0000674 EFI_STATUS Status;
675 EFI_FILE_INFO *FileInfo;
jaben carsey21a86a72015-01-13 22:16:41 +0000676 CHAR16 *FileNameCopy;
Yao Jiewendd17e3f2015-12-25 01:24:16 +0000677 EFI_STATUS Status2;
jcarsey94b17fa2009-05-07 18:46:18 +0000678
679 //
680 // ASSERT if FileName is NULL
681 //
682 ASSERT(FileName != NULL);
683
jcarseya405b862010-09-14 05:18:09 +0000684 if (FileName == NULL) {
685 return (EFI_INVALID_PARAMETER);
686 }
687
jcarsey366f81a2011-06-27 21:04:22 +0000688 if (gEfiShellProtocol != NULL) {
jaben carsey21a86a72015-01-13 22:16:41 +0000689 if ((OpenMode & EFI_FILE_MODE_CREATE) == EFI_FILE_MODE_CREATE) {
690
691 //
692 // Create only a directory
693 //
694 if ((Attributes & EFI_FILE_DIRECTORY) == EFI_FILE_DIRECTORY) {
695 return ShellCreateDirectory(FileName, FileHandle);
696 }
697
698 //
699 // Create the directory to create the file in
700 //
701 FileNameCopy = AllocateCopyPool (StrSize (FileName), FileName);
702 if (FileName == NULL) {
703 return (EFI_OUT_OF_RESOURCES);
704 }
705 PathCleanUpDirectories (FileNameCopy);
706 if (PathRemoveLastItem (FileNameCopy)) {
Jaben Carsey983fffd2015-07-28 20:22:26 +0000707 if (!EFI_ERROR(ShellCreateDirectory (FileNameCopy, FileHandle))) {
708 ShellCloseFile (FileHandle);
709 }
jaben carsey21a86a72015-01-13 22:16:41 +0000710 }
711 SHELL_FREE_NON_NULL (FileNameCopy);
jcarseya405b862010-09-14 05:18:09 +0000712 }
jaben carsey21a86a72015-01-13 22:16:41 +0000713
jcarsey94b17fa2009-05-07 18:46:18 +0000714 //
jaben carsey21a86a72015-01-13 22:16:41 +0000715 // Use UEFI Shell 2.0 method to create the file
jcarsey94b17fa2009-05-07 18:46:18 +0000716 //
jcarsey366f81a2011-06-27 21:04:22 +0000717 Status = gEfiShellProtocol->OpenFileByName(FileName,
jcarseyb1f95a02009-06-16 00:23:19 +0000718 FileHandle,
719 OpenMode);
jcarseya405b862010-09-14 05:18:09 +0000720 if (StrCmp(FileName, L"NUL") != 0 && !EFI_ERROR(Status) && ((OpenMode & EFI_FILE_MODE_CREATE) != 0)){
jcarsey2247dde2009-11-09 18:08:58 +0000721 FileInfo = FileFunctionMap.GetFileInfo(*FileHandle);
jcarseyb1f95a02009-06-16 00:23:19 +0000722 ASSERT(FileInfo != NULL);
723 FileInfo->Attribute = Attributes;
Yao Jiewendd17e3f2015-12-25 01:24:16 +0000724 Status2 = FileFunctionMap.SetFileInfo(*FileHandle, FileInfo);
jcarsey2247dde2009-11-09 18:08:58 +0000725 FreePool(FileInfo);
Yao Jiewendd17e3f2015-12-25 01:24:16 +0000726 if (EFI_ERROR (Status2)) {
727 gEfiShellProtocol->CloseFile(*FileHandle);
728 }
729 Status = Status2;
jcarseyb1f95a02009-06-16 00:23:19 +0000730 }
731 return (Status);
jcarsey1e6e84c2010-01-25 20:05:08 +0000732 }
jcarsey94b17fa2009-05-07 18:46:18 +0000733 //
734 // Using EFI Shell version
735 // this means convert name to path and call that function
736 // since this will use EFI method again that will open it.
737 //
738 ASSERT(mEfiShellEnvironment2 != NULL);
jcarseyb82bfcc2009-06-29 16:28:23 +0000739 FilePath = mEfiShellEnvironment2->NameToPath ((CHAR16*)FileName);
xdu290bfa222010-07-19 05:21:27 +0000740 if (FilePath != NULL) {
jcarsey94b17fa2009-05-07 18:46:18 +0000741 return (ShellOpenFileByDevicePath(&FilePath,
742 &DeviceHandle,
743 FileHandle,
744 OpenMode,
jcarseya405b862010-09-14 05:18:09 +0000745 Attributes));
jcarsey94b17fa2009-05-07 18:46:18 +0000746 }
747 return (EFI_DEVICE_ERROR);
748}
749/**
750 This function create a directory
751
jcarsey1e6e84c2010-01-25 20:05:08 +0000752 If return is EFI_SUCCESS, the Filehandle is the opened directory's handle;
753 otherwise, the Filehandle is NULL. If the directory already existed, this
jcarsey94b17fa2009-05-07 18:46:18 +0000754 function opens the existing directory.
755
darylm503b0934ac2011-11-12 00:35:11 +0000756 @param DirectoryName pointer to directory name
757 @param FileHandle pointer to the file handle.
jcarsey94b17fa2009-05-07 18:46:18 +0000758
darylm503b0934ac2011-11-12 00:35:11 +0000759 @retval EFI_SUCCESS The information was set.
760 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
761 @retval EFI_UNSUPPORTED Could not open the file path.
762 @retval EFI_NOT_FOUND The specified file could not be found on the
jcarsey1e6e84c2010-01-25 20:05:08 +0000763 device or the file system could not be found
jcarsey94b17fa2009-05-07 18:46:18 +0000764 on the device.
darylm503b0934ac2011-11-12 00:35:11 +0000765 @retval EFI_NO_MEDIA The device has no medium.
766 @retval EFI_MEDIA_CHANGED The device has a different medium in it or the
jcarsey94b17fa2009-05-07 18:46:18 +0000767 medium is no longer supported.
darylm503b0934ac2011-11-12 00:35:11 +0000768 @retval EFI_DEVICE_ERROR The device reported an error.
769 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
770 @retval EFI_WRITE_PROTECTED The file or medium is write protected.
771 @retval EFI_ACCESS_DENIED The file was opened read only.
772 @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the
jcarsey94b17fa2009-05-07 18:46:18 +0000773 file.
darylm503b0934ac2011-11-12 00:35:11 +0000774 @retval EFI_VOLUME_FULL The volume is full.
jcarsey94b17fa2009-05-07 18:46:18 +0000775 @sa ShellOpenFileByName
776**/
777EFI_STATUS
778EFIAPI
779ShellCreateDirectory(
jcarseyb82bfcc2009-06-29 16:28:23 +0000780 IN CONST CHAR16 *DirectoryName,
jcarseya405b862010-09-14 05:18:09 +0000781 OUT SHELL_FILE_HANDLE *FileHandle
782 )
783{
jcarsey366f81a2011-06-27 21:04:22 +0000784 if (gEfiShellProtocol != NULL) {
jcarsey2247dde2009-11-09 18:08:58 +0000785 //
786 // Use UEFI Shell 2.0 method
787 //
jcarsey366f81a2011-06-27 21:04:22 +0000788 return (gEfiShellProtocol->CreateFile(DirectoryName,
jcarsey2247dde2009-11-09 18:08:58 +0000789 EFI_FILE_DIRECTORY,
790 FileHandle
jcarseya405b862010-09-14 05:18:09 +0000791 ));
jcarsey2247dde2009-11-09 18:08:58 +0000792 } else {
793 return (ShellOpenFileByName(DirectoryName,
794 FileHandle,
795 EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE,
796 EFI_FILE_DIRECTORY
jcarseya405b862010-09-14 05:18:09 +0000797 ));
jcarsey2247dde2009-11-09 18:08:58 +0000798 }
jcarsey94b17fa2009-05-07 18:46:18 +0000799}
800
801/**
802 This function reads information from an opened file.
803
jcarsey1e6e84c2010-01-25 20:05:08 +0000804 If FileHandle is not a directory, the function reads the requested number of
805 bytes from the file at the file's current position and returns them in Buffer.
jcarsey94b17fa2009-05-07 18:46:18 +0000806 If the read goes beyond the end of the file, the read length is truncated to the
jcarsey1e6e84c2010-01-25 20:05:08 +0000807 end of the file. The file's current position is increased by the number of bytes
808 returned. If FileHandle is a directory, the function reads the directory entry
809 at the file's current position and returns the entry in Buffer. If the Buffer
810 is not large enough to hold the current directory entry, then
811 EFI_BUFFER_TOO_SMALL is returned and the current file position is not updated.
812 BufferSize is set to be the size of the buffer needed to read the entry. On
813 success, the current position is updated to the next directory entry. If there
814 are no more directory entries, the read returns a zero-length buffer.
jcarsey94b17fa2009-05-07 18:46:18 +0000815 EFI_FILE_INFO is the structure returned as the directory entry.
816
817 @param FileHandle the opened file handle
jcarsey1e6e84c2010-01-25 20:05:08 +0000818 @param BufferSize on input the size of buffer in bytes. on return
jcarsey94b17fa2009-05-07 18:46:18 +0000819 the number of bytes written.
820 @param Buffer the buffer to put read data into.
821
darylm503b0934ac2011-11-12 00:35:11 +0000822 @retval EFI_SUCCESS Data was read.
823 @retval EFI_NO_MEDIA The device has no media.
824 @retval EFI_DEVICE_ERROR The device reported an error.
825 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
826 @retval EFI_BUFFER_TO_SMALL Buffer is too small. ReadSize contains required
jcarsey94b17fa2009-05-07 18:46:18 +0000827 size.
828
829**/
830EFI_STATUS
831EFIAPI
832ShellReadFile(
jcarseya405b862010-09-14 05:18:09 +0000833 IN SHELL_FILE_HANDLE FileHandle,
jcarsey94b17fa2009-05-07 18:46:18 +0000834 IN OUT UINTN *BufferSize,
835 OUT VOID *Buffer
jcarseya405b862010-09-14 05:18:09 +0000836 )
837{
jcarseyd2b45642009-05-11 18:02:16 +0000838 return (FileFunctionMap.ReadFile(FileHandle, BufferSize, Buffer));
jcarsey94b17fa2009-05-07 18:46:18 +0000839}
840
841
842/**
843 Write data to a file.
844
jcarsey1e6e84c2010-01-25 20:05:08 +0000845 This function writes the specified number of bytes to the file at the current
846 file position. The current file position is advanced the actual number of bytes
847 written, which is returned in BufferSize. Partial writes only occur when there
848 has been a data error during the write attempt (such as "volume space full").
849 The file is automatically grown to hold the data if required. Direct writes to
jcarsey94b17fa2009-05-07 18:46:18 +0000850 opened directories are not supported.
851
852 @param FileHandle The opened file for writing
853 @param BufferSize on input the number of bytes in Buffer. On output
854 the number of bytes written.
855 @param Buffer the buffer containing data to write is stored.
856
darylm503b0934ac2011-11-12 00:35:11 +0000857 @retval EFI_SUCCESS Data was written.
858 @retval EFI_UNSUPPORTED Writes to an open directory are not supported.
859 @retval EFI_NO_MEDIA The device has no media.
860 @retval EFI_DEVICE_ERROR The device reported an error.
861 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
862 @retval EFI_WRITE_PROTECTED The device is write-protected.
863 @retval EFI_ACCESS_DENIED The file was open for read only.
864 @retval EFI_VOLUME_FULL The volume is full.
jcarsey94b17fa2009-05-07 18:46:18 +0000865**/
866EFI_STATUS
867EFIAPI
868ShellWriteFile(
jcarsey252d9452011-03-25 20:49:53 +0000869 IN SHELL_FILE_HANDLE FileHandle,
jcarsey94b17fa2009-05-07 18:46:18 +0000870 IN OUT UINTN *BufferSize,
871 IN VOID *Buffer
jcarseya405b862010-09-14 05:18:09 +0000872 )
873{
jcarseyd2b45642009-05-11 18:02:16 +0000874 return (FileFunctionMap.WriteFile(FileHandle, BufferSize, Buffer));
jcarsey94b17fa2009-05-07 18:46:18 +0000875}
876
jcarsey1e6e84c2010-01-25 20:05:08 +0000877/**
jcarsey94b17fa2009-05-07 18:46:18 +0000878 Close an open file handle.
879
jcarsey1e6e84c2010-01-25 20:05:08 +0000880 This function closes a specified file handle. All "dirty" cached file data is
881 flushed to the device, and the file is closed. In all cases the handle is
jcarsey94b17fa2009-05-07 18:46:18 +0000882 closed.
883
884@param FileHandle the file handle to close.
885
886@retval EFI_SUCCESS the file handle was closed sucessfully.
887**/
888EFI_STATUS
889EFIAPI
890ShellCloseFile (
jcarseya405b862010-09-14 05:18:09 +0000891 IN SHELL_FILE_HANDLE *FileHandle
892 )
893{
jcarseyd2b45642009-05-11 18:02:16 +0000894 return (FileFunctionMap.CloseFile(*FileHandle));
jcarsey94b17fa2009-05-07 18:46:18 +0000895}
896
897/**
898 Delete a file and close the handle
899
900 This function closes and deletes a file. In all cases the file handle is closed.
jcarsey1e6e84c2010-01-25 20:05:08 +0000901 If the file cannot be deleted, the warning code EFI_WARN_DELETE_FAILURE is
jcarsey94b17fa2009-05-07 18:46:18 +0000902 returned, but the handle is still closed.
903
904 @param FileHandle the file handle to delete
905
906 @retval EFI_SUCCESS the file was closed sucessfully
jcarsey1e6e84c2010-01-25 20:05:08 +0000907 @retval EFI_WARN_DELETE_FAILURE the handle was closed, but the file was not
jcarsey94b17fa2009-05-07 18:46:18 +0000908 deleted
darylm503b0934ac2011-11-12 00:35:11 +0000909 @retval INVALID_PARAMETER One of the parameters has an invalid value.
jcarsey94b17fa2009-05-07 18:46:18 +0000910**/
911EFI_STATUS
912EFIAPI
913ShellDeleteFile (
darylm503b0934ac2011-11-12 00:35:11 +0000914 IN SHELL_FILE_HANDLE *FileHandle
jcarseya405b862010-09-14 05:18:09 +0000915 )
916{
jcarseyd2b45642009-05-11 18:02:16 +0000917 return (FileFunctionMap.DeleteFile(*FileHandle));
jcarsey94b17fa2009-05-07 18:46:18 +0000918}
919
920/**
921 Set the current position in a file.
922
jcarsey1e6e84c2010-01-25 20:05:08 +0000923 This function sets the current file position for the handle to the position
jcarsey94b17fa2009-05-07 18:46:18 +0000924 supplied. With the exception of seeking to position 0xFFFFFFFFFFFFFFFF, only
jcarsey1e6e84c2010-01-25 20:05:08 +0000925 absolute positioning is supported, and seeking past the end of the file is
926 allowed (a subsequent write would grow the file). Seeking to position
jcarsey94b17fa2009-05-07 18:46:18 +0000927 0xFFFFFFFFFFFFFFFF causes the current position to be set to the end of the file.
jcarsey1e6e84c2010-01-25 20:05:08 +0000928 If FileHandle is a directory, the only position that may be set is zero. This
jcarsey94b17fa2009-05-07 18:46:18 +0000929 has the effect of starting the read process of the directory entries over.
930
931 @param FileHandle The file handle on which the position is being set
932 @param Position Byte position from begining of file
933
934 @retval EFI_SUCCESS Operation completed sucessfully.
jcarsey1e6e84c2010-01-25 20:05:08 +0000935 @retval EFI_UNSUPPORTED the seek request for non-zero is not valid on
jcarsey94b17fa2009-05-07 18:46:18 +0000936 directories.
937 @retval INVALID_PARAMETER One of the parameters has an invalid value.
938**/
939EFI_STATUS
940EFIAPI
941ShellSetFilePosition (
darylm503b0934ac2011-11-12 00:35:11 +0000942 IN SHELL_FILE_HANDLE FileHandle,
943 IN UINT64 Position
jcarseya405b862010-09-14 05:18:09 +0000944 )
945{
jcarseyd2b45642009-05-11 18:02:16 +0000946 return (FileFunctionMap.SetFilePosition(FileHandle, Position));
jcarsey94b17fa2009-05-07 18:46:18 +0000947}
948
jcarsey1e6e84c2010-01-25 20:05:08 +0000949/**
jcarsey94b17fa2009-05-07 18:46:18 +0000950 Gets a file's current position
951
jcarsey1e6e84c2010-01-25 20:05:08 +0000952 This function retrieves the current file position for the file handle. For
953 directories, the current file position has no meaning outside of the file
jcarsey94b17fa2009-05-07 18:46:18 +0000954 system driver and as such the operation is not supported. An error is returned
955 if FileHandle is a directory.
956
957 @param FileHandle The open file handle on which to get the position.
958 @param Position Byte position from begining of file.
959
960 @retval EFI_SUCCESS the operation completed sucessfully.
961 @retval INVALID_PARAMETER One of the parameters has an invalid value.
962 @retval EFI_UNSUPPORTED the request is not valid on directories.
963**/
964EFI_STATUS
965EFIAPI
966ShellGetFilePosition (
jcarseya405b862010-09-14 05:18:09 +0000967 IN SHELL_FILE_HANDLE FileHandle,
jcarsey94b17fa2009-05-07 18:46:18 +0000968 OUT UINT64 *Position
jcarseya405b862010-09-14 05:18:09 +0000969 )
970{
jcarseyd2b45642009-05-11 18:02:16 +0000971 return (FileFunctionMap.GetFilePosition(FileHandle, Position));
jcarsey94b17fa2009-05-07 18:46:18 +0000972}
973/**
974 Flushes data on a file
jcarsey1e6e84c2010-01-25 20:05:08 +0000975
jcarsey94b17fa2009-05-07 18:46:18 +0000976 This function flushes all modified data associated with a file to a device.
977
978 @param FileHandle The file handle on which to flush data
979
980 @retval EFI_SUCCESS The data was flushed.
981 @retval EFI_NO_MEDIA The device has no media.
982 @retval EFI_DEVICE_ERROR The device reported an error.
983 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
984 @retval EFI_WRITE_PROTECTED The file or medium is write protected.
985 @retval EFI_ACCESS_DENIED The file was opened for read only.
986**/
987EFI_STATUS
988EFIAPI
989ShellFlushFile (
jcarseya405b862010-09-14 05:18:09 +0000990 IN SHELL_FILE_HANDLE FileHandle
991 )
992{
jcarseyd2b45642009-05-11 18:02:16 +0000993 return (FileFunctionMap.FlushFile(FileHandle));
jcarsey94b17fa2009-05-07 18:46:18 +0000994}
995
darylm503b0934ac2011-11-12 00:35:11 +0000996/** Retrieve first entry from a directory.
jcarsey94b17fa2009-05-07 18:46:18 +0000997
darylm503b0934ac2011-11-12 00:35:11 +0000998 This function takes an open directory handle and gets information from the
999 first entry in the directory. A buffer is allocated to contain
1000 the information and a pointer to the buffer is returned in *Buffer. The
1001 caller can use ShellFindNextFile() to get subsequent directory entries.
jcarsey94b17fa2009-05-07 18:46:18 +00001002
darylm503b0934ac2011-11-12 00:35:11 +00001003 The buffer will be freed by ShellFindNextFile() when the last directory
1004 entry is read. Otherwise, the caller must free the buffer, using FreePool,
1005 when finished with it.
1006
1007 @param[in] DirHandle The file handle of the directory to search.
1008 @param[out] Buffer The pointer to the buffer for the file's information.
jcarsey94b17fa2009-05-07 18:46:18 +00001009
1010 @retval EFI_SUCCESS Found the first file.
1011 @retval EFI_NOT_FOUND Cannot find the directory.
1012 @retval EFI_NO_MEDIA The device has no media.
1013 @retval EFI_DEVICE_ERROR The device reported an error.
1014 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1015 @return Others status of ShellGetFileInfo, ShellSetFilePosition,
1016 or ShellReadFile
1017**/
1018EFI_STATUS
1019EFIAPI
1020ShellFindFirstFile (
jcarseya405b862010-09-14 05:18:09 +00001021 IN SHELL_FILE_HANDLE DirHandle,
jcarseyd2b45642009-05-11 18:02:16 +00001022 OUT EFI_FILE_INFO **Buffer
jcarseya405b862010-09-14 05:18:09 +00001023 )
1024{
jcarsey94b17fa2009-05-07 18:46:18 +00001025 //
jcarseyd2b45642009-05-11 18:02:16 +00001026 // pass to file handle lib
jcarsey94b17fa2009-05-07 18:46:18 +00001027 //
jcarseyd2b45642009-05-11 18:02:16 +00001028 return (FileHandleFindFirstFile(DirHandle, Buffer));
jcarsey94b17fa2009-05-07 18:46:18 +00001029}
darylm503b0934ac2011-11-12 00:35:11 +00001030/** Retrieve next entries from a directory.
jcarsey94b17fa2009-05-07 18:46:18 +00001031
darylm503b0934ac2011-11-12 00:35:11 +00001032 To use this function, the caller must first call the ShellFindFirstFile()
1033 function to get the first directory entry. Subsequent directory entries are
1034 retrieved by using the ShellFindNextFile() function. This function can
1035 be called several times to get each entry from the directory. If the call of
1036 ShellFindNextFile() retrieved the last directory entry, the next call of
1037 this function will set *NoFile to TRUE and free the buffer.
jcarsey94b17fa2009-05-07 18:46:18 +00001038
darylm503b0934ac2011-11-12 00:35:11 +00001039 @param[in] DirHandle The file handle of the directory.
1040 @param[out] Buffer The pointer to buffer for file's information.
1041 @param[out] NoFile The pointer to boolean when last file is found.
jcarsey94b17fa2009-05-07 18:46:18 +00001042
1043 @retval EFI_SUCCESS Found the next file, or reached last file
1044 @retval EFI_NO_MEDIA The device has no media.
1045 @retval EFI_DEVICE_ERROR The device reported an error.
1046 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1047**/
1048EFI_STATUS
1049EFIAPI
1050ShellFindNextFile(
jcarseya405b862010-09-14 05:18:09 +00001051 IN SHELL_FILE_HANDLE DirHandle,
jcarsey94b17fa2009-05-07 18:46:18 +00001052 OUT EFI_FILE_INFO *Buffer,
1053 OUT BOOLEAN *NoFile
jcarseya405b862010-09-14 05:18:09 +00001054 )
1055{
jcarsey94b17fa2009-05-07 18:46:18 +00001056 //
jcarseyd2b45642009-05-11 18:02:16 +00001057 // pass to file handle lib
jcarsey94b17fa2009-05-07 18:46:18 +00001058 //
jcarseyd2b45642009-05-11 18:02:16 +00001059 return (FileHandleFindNextFile(DirHandle, Buffer, NoFile));
jcarsey94b17fa2009-05-07 18:46:18 +00001060}
1061/**
1062 Retrieve the size of a file.
1063
1064 if FileHandle is NULL then ASSERT()
1065 if Size is NULL then ASSERT()
1066
jcarsey1e6e84c2010-01-25 20:05:08 +00001067 This function extracts the file size info from the FileHandle's EFI_FILE_INFO
jcarsey94b17fa2009-05-07 18:46:18 +00001068 data.
1069
1070 @param FileHandle file handle from which size is retrieved
1071 @param Size pointer to size
1072
1073 @retval EFI_SUCCESS operation was completed sucessfully
1074 @retval EFI_DEVICE_ERROR cannot access the file
1075**/
1076EFI_STATUS
1077EFIAPI
1078ShellGetFileSize (
jcarseya405b862010-09-14 05:18:09 +00001079 IN SHELL_FILE_HANDLE FileHandle,
jcarsey94b17fa2009-05-07 18:46:18 +00001080 OUT UINT64 *Size
jcarseya405b862010-09-14 05:18:09 +00001081 )
1082{
jcarseyd2b45642009-05-11 18:02:16 +00001083 return (FileFunctionMap.GetFileSize(FileHandle, Size));
jcarsey94b17fa2009-05-07 18:46:18 +00001084}
1085/**
1086 Retrieves the status of the break execution flag
1087
1088 this function is useful to check whether the application is being asked to halt by the shell.
1089
1090 @retval TRUE the execution break is enabled
1091 @retval FALSE the execution break is not enabled
1092**/
1093BOOLEAN
1094EFIAPI
1095ShellGetExecutionBreakFlag(
1096 VOID
1097 )
1098{
jcarsey1e6e84c2010-01-25 20:05:08 +00001099 //
jcarsey94b17fa2009-05-07 18:46:18 +00001100 // Check for UEFI Shell 2.0 protocols
1101 //
jcarsey366f81a2011-06-27 21:04:22 +00001102 if (gEfiShellProtocol != NULL) {
jcarsey94b17fa2009-05-07 18:46:18 +00001103
1104 //
1105 // We are using UEFI Shell 2.0; see if the event has been triggered
1106 //
jcarsey366f81a2011-06-27 21:04:22 +00001107 if (gBS->CheckEvent(gEfiShellProtocol->ExecutionBreak) != EFI_SUCCESS) {
jcarsey94b17fa2009-05-07 18:46:18 +00001108 return (FALSE);
1109 }
1110 return (TRUE);
jcarsey1e6e84c2010-01-25 20:05:08 +00001111 }
jcarsey94b17fa2009-05-07 18:46:18 +00001112
1113 //
1114 // using EFI Shell; call the function to check
1115 //
jcarsey92a54472011-06-27 20:33:13 +00001116 if (mEfiShellEnvironment2 != NULL) {
1117 return (mEfiShellEnvironment2->GetExecutionBreak());
1118 }
1119
1120 return (FALSE);
jcarsey94b17fa2009-05-07 18:46:18 +00001121}
1122/**
1123 return the value of an environment variable
1124
jcarsey1e6e84c2010-01-25 20:05:08 +00001125 this function gets the value of the environment variable set by the
jcarsey94b17fa2009-05-07 18:46:18 +00001126 ShellSetEnvironmentVariable function
1127
1128 @param EnvKey The key name of the environment variable.
1129
1130 @retval NULL the named environment variable does not exist.
1131 @return != NULL pointer to the value of the environment variable
1132**/
1133CONST CHAR16*
1134EFIAPI
1135ShellGetEnvironmentVariable (
jcarsey9b3bf082009-06-23 21:15:07 +00001136 IN CONST CHAR16 *EnvKey
jcarsey94b17fa2009-05-07 18:46:18 +00001137 )
1138{
jcarsey1e6e84c2010-01-25 20:05:08 +00001139 //
jcarsey94b17fa2009-05-07 18:46:18 +00001140 // Check for UEFI Shell 2.0 protocols
1141 //
jcarsey366f81a2011-06-27 21:04:22 +00001142 if (gEfiShellProtocol != NULL) {
1143 return (gEfiShellProtocol->GetEnv(EnvKey));
jcarsey94b17fa2009-05-07 18:46:18 +00001144 }
1145
1146 //
jcarsey92a54472011-06-27 20:33:13 +00001147 // Check for EFI shell
jcarsey94b17fa2009-05-07 18:46:18 +00001148 //
jcarsey92a54472011-06-27 20:33:13 +00001149 if (mEfiShellEnvironment2 != NULL) {
1150 return (mEfiShellEnvironment2->GetEnv((CHAR16*)EnvKey));
1151 }
jcarsey94b17fa2009-05-07 18:46:18 +00001152
jcarsey92a54472011-06-27 20:33:13 +00001153 return NULL;
jcarsey94b17fa2009-05-07 18:46:18 +00001154}
1155/**
1156 set the value of an environment variable
1157
1158This function changes the current value of the specified environment variable. If the
1159environment variable exists and the Value is an empty string, then the environment
1160variable is deleted. If the environment variable exists and the Value is not an empty
1161string, then the value of the environment variable is changed. If the environment
1162variable does not exist and the Value is an empty string, there is no action. If the
1163environment variable does not exist and the Value is a non-empty string, then the
1164environment variable is created and assigned the specified value.
1165
1166 This is not supported pre-UEFI Shell 2.0.
1167
1168 @param EnvKey The key name of the environment variable.
1169 @param EnvVal The Value of the environment variable
1170 @param Volatile Indicates whether the variable is non-volatile (FALSE) or volatile (TRUE).
1171
1172 @retval EFI_SUCCESS the operation was completed sucessfully
1173 @retval EFI_UNSUPPORTED This operation is not allowed in pre UEFI 2.0 Shell environments
1174**/
1175EFI_STATUS
1176EFIAPI
1177ShellSetEnvironmentVariable (
1178 IN CONST CHAR16 *EnvKey,
1179 IN CONST CHAR16 *EnvVal,
1180 IN BOOLEAN Volatile
1181 )
1182{
jcarsey1e6e84c2010-01-25 20:05:08 +00001183 //
jcarsey94b17fa2009-05-07 18:46:18 +00001184 // Check for UEFI Shell 2.0 protocols
1185 //
jcarsey366f81a2011-06-27 21:04:22 +00001186 if (gEfiShellProtocol != NULL) {
1187 return (gEfiShellProtocol->SetEnv(EnvKey, EnvVal, Volatile));
jcarsey1e6e84c2010-01-25 20:05:08 +00001188 }
jcarsey94b17fa2009-05-07 18:46:18 +00001189
1190 //
1191 // This feature does not exist under EFI shell
1192 //
1193 return (EFI_UNSUPPORTED);
1194}
jcarseya405b862010-09-14 05:18:09 +00001195
jcarsey94b17fa2009-05-07 18:46:18 +00001196/**
jcarseya405b862010-09-14 05:18:09 +00001197 Cause the shell to parse and execute a command line.
jcarsey94b17fa2009-05-07 18:46:18 +00001198
1199 This function creates a nested instance of the shell and executes the specified
jcarseya405b862010-09-14 05:18:09 +00001200 command (CommandLine) with the specified environment (Environment). Upon return,
1201 the status code returned by the specified command is placed in StatusCode.
1202 If Environment is NULL, then the current environment is used and all changes made
1203 by the commands executed will be reflected in the current environment. If the
1204 Environment is non-NULL, then the changes made will be discarded.
1205 The CommandLine is executed from the current working directory on the current
1206 device.
jcarsey94b17fa2009-05-07 18:46:18 +00001207
Brendan Jackman3877d0f2014-01-24 22:31:07 +00001208 The EnvironmentVariables pararemeter is ignored in a pre-UEFI Shell 2.0
jcarseya405b862010-09-14 05:18:09 +00001209 environment. The values pointed to by the parameters will be unchanged by the
1210 ShellExecute() function. The Output parameter has no effect in a
1211 UEFI Shell 2.0 environment.
jcarsey94b17fa2009-05-07 18:46:18 +00001212
jcarseya405b862010-09-14 05:18:09 +00001213 @param[in] ParentHandle The parent image starting the operation.
1214 @param[in] CommandLine The pointer to a NULL terminated command line.
1215 @param[in] Output True to display debug output. False to hide it.
1216 @param[in] EnvironmentVariables Optional pointer to array of environment variables
1217 in the form "x=y". If NULL, the current set is used.
1218 @param[out] Status The status of the run command line.
jcarsey94b17fa2009-05-07 18:46:18 +00001219
jcarseya405b862010-09-14 05:18:09 +00001220 @retval EFI_SUCCESS The operation completed sucessfully. Status
1221 contains the status code returned.
1222 @retval EFI_INVALID_PARAMETER A parameter contains an invalid value.
1223 @retval EFI_OUT_OF_RESOURCES Out of resources.
1224 @retval EFI_UNSUPPORTED The operation is not allowed.
jcarsey94b17fa2009-05-07 18:46:18 +00001225**/
1226EFI_STATUS
1227EFIAPI
1228ShellExecute (
1229 IN EFI_HANDLE *ParentHandle,
1230 IN CHAR16 *CommandLine OPTIONAL,
1231 IN BOOLEAN Output OPTIONAL,
1232 IN CHAR16 **EnvironmentVariables OPTIONAL,
1233 OUT EFI_STATUS *Status OPTIONAL
1234 )
1235{
Brendan Jackman3877d0f2014-01-24 22:31:07 +00001236 EFI_STATUS CmdStatus;
jcarsey1e6e84c2010-01-25 20:05:08 +00001237 //
jcarsey94b17fa2009-05-07 18:46:18 +00001238 // Check for UEFI Shell 2.0 protocols
1239 //
jcarsey366f81a2011-06-27 21:04:22 +00001240 if (gEfiShellProtocol != NULL) {
jcarsey94b17fa2009-05-07 18:46:18 +00001241 //
1242 // Call UEFI Shell 2.0 version (not using Output parameter)
1243 //
jcarsey366f81a2011-06-27 21:04:22 +00001244 return (gEfiShellProtocol->Execute(ParentHandle,
jcarsey94b17fa2009-05-07 18:46:18 +00001245 CommandLine,
1246 EnvironmentVariables,
1247 Status));
jcarsey1e6e84c2010-01-25 20:05:08 +00001248 }
jcarsey92a54472011-06-27 20:33:13 +00001249
jcarsey94b17fa2009-05-07 18:46:18 +00001250 //
jcarsey92a54472011-06-27 20:33:13 +00001251 // Check for EFI shell
jcarsey94b17fa2009-05-07 18:46:18 +00001252 //
jcarsey92a54472011-06-27 20:33:13 +00001253 if (mEfiShellEnvironment2 != NULL) {
1254 //
Brendan Jackman3877d0f2014-01-24 22:31:07 +00001255 // Call EFI Shell version.
jcarsey92a54472011-06-27 20:33:13 +00001256 // Due to oddity in the EFI shell we want to dereference the ParentHandle here
1257 //
Brendan Jackman3877d0f2014-01-24 22:31:07 +00001258 CmdStatus = (mEfiShellEnvironment2->Execute(*ParentHandle,
jcarsey92a54472011-06-27 20:33:13 +00001259 CommandLine,
1260 Output));
Brendan Jackman3877d0f2014-01-24 22:31:07 +00001261 //
1262 // No Status output parameter so just use the returned status
1263 //
1264 if (Status != NULL) {
1265 *Status = CmdStatus;
1266 }
1267 //
1268 // If there was an error, we can't tell if it was from the command or from
1269 // the Execute() function, so we'll just assume the shell ran successfully
1270 // and the error came from the command.
1271 //
1272 return EFI_SUCCESS;
jcarsey92a54472011-06-27 20:33:13 +00001273 }
1274
1275 return (EFI_UNSUPPORTED);
jcarsey94b17fa2009-05-07 18:46:18 +00001276}
Brendan Jackman3877d0f2014-01-24 22:31:07 +00001277
jcarsey94b17fa2009-05-07 18:46:18 +00001278/**
1279 Retreives the current directory path
1280
jcarsey1e6e84c2010-01-25 20:05:08 +00001281 If the DeviceName is NULL, it returns the current device's current directory
1282 name. If the DeviceName is not NULL, it returns the current directory name
jcarsey94b17fa2009-05-07 18:46:18 +00001283 on specified drive.
1284
Qiu Shuminfbd2dfa2015-10-23 02:03:20 +00001285 Note that the current directory string should exclude the tailing backslash character.
1286
jcarsey94b17fa2009-05-07 18:46:18 +00001287 @param DeviceName the name of the drive to get directory on
1288
1289 @retval NULL the directory does not exist
1290 @return != NULL the directory
1291**/
1292CONST CHAR16*
1293EFIAPI
1294ShellGetCurrentDir (
jcarseya405b862010-09-14 05:18:09 +00001295 IN CHAR16 * CONST DeviceName OPTIONAL
jcarsey94b17fa2009-05-07 18:46:18 +00001296 )
1297{
jcarsey1e6e84c2010-01-25 20:05:08 +00001298 //
jcarsey94b17fa2009-05-07 18:46:18 +00001299 // Check for UEFI Shell 2.0 protocols
1300 //
jcarsey366f81a2011-06-27 21:04:22 +00001301 if (gEfiShellProtocol != NULL) {
1302 return (gEfiShellProtocol->GetCurDir(DeviceName));
jcarsey1e6e84c2010-01-25 20:05:08 +00001303 }
jcarsey92a54472011-06-27 20:33:13 +00001304
jcarsey94b17fa2009-05-07 18:46:18 +00001305 //
jcarsey8bd282b2011-06-27 16:45:41 +00001306 // Check for EFI shell
jcarsey94b17fa2009-05-07 18:46:18 +00001307 //
jcarsey8bd282b2011-06-27 16:45:41 +00001308 if (mEfiShellEnvironment2 != NULL) {
1309 return (mEfiShellEnvironment2->CurDir(DeviceName));
1310 }
1311
1312 return (NULL);
jcarsey94b17fa2009-05-07 18:46:18 +00001313}
1314/**
1315 sets (enabled or disabled) the page break mode
1316
jcarsey1e6e84c2010-01-25 20:05:08 +00001317 when page break mode is enabled the screen will stop scrolling
jcarsey94b17fa2009-05-07 18:46:18 +00001318 and wait for operator input before scrolling a subsequent screen.
1319
1320 @param CurrentState TRUE to enable and FALSE to disable
1321**/
jcarsey1e6e84c2010-01-25 20:05:08 +00001322VOID
jcarsey94b17fa2009-05-07 18:46:18 +00001323EFIAPI
1324ShellSetPageBreakMode (
1325 IN BOOLEAN CurrentState
1326 )
1327{
1328 //
1329 // check for enabling
1330 //
1331 if (CurrentState != 0x00) {
jcarsey1e6e84c2010-01-25 20:05:08 +00001332 //
jcarsey94b17fa2009-05-07 18:46:18 +00001333 // check for UEFI Shell 2.0
1334 //
jcarsey366f81a2011-06-27 21:04:22 +00001335 if (gEfiShellProtocol != NULL) {
jcarsey94b17fa2009-05-07 18:46:18 +00001336 //
1337 // Enable with UEFI 2.0 Shell
1338 //
jcarsey366f81a2011-06-27 21:04:22 +00001339 gEfiShellProtocol->EnablePageBreak();
jcarsey94b17fa2009-05-07 18:46:18 +00001340 return;
1341 } else {
jcarsey1e6e84c2010-01-25 20:05:08 +00001342 //
jcarsey92a54472011-06-27 20:33:13 +00001343 // Check for EFI shell
jcarsey94b17fa2009-05-07 18:46:18 +00001344 //
jcarsey92a54472011-06-27 20:33:13 +00001345 if (mEfiShellEnvironment2 != NULL) {
1346 //
1347 // Enable with EFI Shell
1348 //
1349 mEfiShellEnvironment2->EnablePageBreak (DEFAULT_INIT_ROW, DEFAULT_AUTO_LF);
1350 return;
1351 }
jcarsey94b17fa2009-05-07 18:46:18 +00001352 }
1353 } else {
jcarsey1e6e84c2010-01-25 20:05:08 +00001354 //
jcarsey94b17fa2009-05-07 18:46:18 +00001355 // check for UEFI Shell 2.0
1356 //
jcarsey366f81a2011-06-27 21:04:22 +00001357 if (gEfiShellProtocol != NULL) {
jcarsey94b17fa2009-05-07 18:46:18 +00001358 //
1359 // Disable with UEFI 2.0 Shell
1360 //
jcarsey366f81a2011-06-27 21:04:22 +00001361 gEfiShellProtocol->DisablePageBreak();
jcarsey94b17fa2009-05-07 18:46:18 +00001362 return;
1363 } else {
jcarsey1e6e84c2010-01-25 20:05:08 +00001364 //
jcarsey92a54472011-06-27 20:33:13 +00001365 // Check for EFI shell
jcarsey94b17fa2009-05-07 18:46:18 +00001366 //
jcarsey92a54472011-06-27 20:33:13 +00001367 if (mEfiShellEnvironment2 != NULL) {
1368 //
1369 // Disable with EFI Shell
1370 //
1371 mEfiShellEnvironment2->DisablePageBreak ();
1372 return;
1373 }
jcarsey94b17fa2009-05-07 18:46:18 +00001374 }
1375 }
1376}
1377
1378///
1379/// version of EFI_SHELL_FILE_INFO struct, except has no CONST pointers.
1380/// This allows for the struct to be populated.
1381///
1382typedef struct {
jcarseyd2b45642009-05-11 18:02:16 +00001383 LIST_ENTRY Link;
jcarsey94b17fa2009-05-07 18:46:18 +00001384 EFI_STATUS Status;
1385 CHAR16 *FullName;
1386 CHAR16 *FileName;
jcarseya405b862010-09-14 05:18:09 +00001387 SHELL_FILE_HANDLE Handle;
jcarsey94b17fa2009-05-07 18:46:18 +00001388 EFI_FILE_INFO *Info;
1389} EFI_SHELL_FILE_INFO_NO_CONST;
1390
1391/**
1392 Converts a EFI shell list of structures to the coresponding UEFI Shell 2.0 type of list.
1393
1394 if OldStyleFileList is NULL then ASSERT()
1395
jcarsey1e6e84c2010-01-25 20:05:08 +00001396 this function will convert a SHELL_FILE_ARG based list into a callee allocated
jcarsey94b17fa2009-05-07 18:46:18 +00001397 EFI_SHELL_FILE_INFO based list. it is up to the caller to free the memory via
1398 the ShellCloseFileMetaArg function.
1399
ydong104ff7e372011-09-02 08:05:34 +00001400 @param[in] FileList the EFI shell list type
1401 @param[in, out] ListHead the list to add to
jcarsey94b17fa2009-05-07 18:46:18 +00001402
1403 @retval the resultant head of the double linked new format list;
1404**/
1405LIST_ENTRY*
1406EFIAPI
1407InternalShellConvertFileListType (
jcarsey9b3bf082009-06-23 21:15:07 +00001408 IN LIST_ENTRY *FileList,
1409 IN OUT LIST_ENTRY *ListHead
jcarsey125c2cf2009-11-18 21:36:50 +00001410 )
1411{
jcarsey94b17fa2009-05-07 18:46:18 +00001412 SHELL_FILE_ARG *OldInfo;
jcarsey9b3bf082009-06-23 21:15:07 +00001413 LIST_ENTRY *Link;
jcarsey94b17fa2009-05-07 18:46:18 +00001414 EFI_SHELL_FILE_INFO_NO_CONST *NewInfo;
1415
1416 //
jcarsey9b3bf082009-06-23 21:15:07 +00001417 // ASSERTs
jcarsey94b17fa2009-05-07 18:46:18 +00001418 //
jcarsey9b3bf082009-06-23 21:15:07 +00001419 ASSERT(FileList != NULL);
1420 ASSERT(ListHead != NULL);
jcarsey94b17fa2009-05-07 18:46:18 +00001421
1422 //
1423 // enumerate through each member of the old list and copy
1424 //
jcarseyd2b45642009-05-11 18:02:16 +00001425 for (Link = FileList->ForwardLink; Link != FileList; Link = Link->ForwardLink) {
jcarsey94b17fa2009-05-07 18:46:18 +00001426 OldInfo = CR (Link, SHELL_FILE_ARG, Link, SHELL_FILE_ARG_SIGNATURE);
jcarseya405b862010-09-14 05:18:09 +00001427 ASSERT(OldInfo != NULL);
1428
1429 //
1430 // Skip ones that failed to open...
1431 //
1432 if (OldInfo->Status != EFI_SUCCESS) {
1433 continue;
1434 }
jcarsey94b17fa2009-05-07 18:46:18 +00001435
1436 //
1437 // make sure the old list was valid
1438 //
jcarsey94b17fa2009-05-07 18:46:18 +00001439 ASSERT(OldInfo->Info != NULL);
1440 ASSERT(OldInfo->FullName != NULL);
1441 ASSERT(OldInfo->FileName != NULL);
1442
1443 //
1444 // allocate a new EFI_SHELL_FILE_INFO object
1445 //
1446 NewInfo = AllocateZeroPool(sizeof(EFI_SHELL_FILE_INFO));
jcarseyc9d92df2010-02-03 15:37:54 +00001447 if (NewInfo == NULL) {
jcarsey7a95efd2011-10-13 16:08:18 +00001448 ShellCloseFileMetaArg((EFI_SHELL_FILE_INFO**)(&ListHead));
jcarseybeab0fc2011-10-10 17:26:25 +00001449 ListHead = NULL;
jcarseyc9d92df2010-02-03 15:37:54 +00001450 break;
1451 }
jcarsey1e6e84c2010-01-25 20:05:08 +00001452
1453 //
jcarsey94b17fa2009-05-07 18:46:18 +00001454 // copy the simple items
1455 //
1456 NewInfo->Handle = OldInfo->Handle;
1457 NewInfo->Status = OldInfo->Status;
1458
jcarseyd2b45642009-05-11 18:02:16 +00001459 // old shell checks for 0 not NULL
1460 OldInfo->Handle = 0;
1461
jcarsey94b17fa2009-05-07 18:46:18 +00001462 //
1463 // allocate new space to copy strings and structure
1464 //
Jaben Carsey98c16be2014-08-19 21:00:34 +00001465 NewInfo->FullName = AllocateCopyPool(StrSize(OldInfo->FullName), OldInfo->FullName);
1466 NewInfo->FileName = AllocateCopyPool(StrSize(OldInfo->FileName), OldInfo->FileName);
1467 NewInfo->Info = AllocateCopyPool((UINTN)OldInfo->Info->Size, OldInfo->Info);
jcarsey1e6e84c2010-01-25 20:05:08 +00001468
jcarsey94b17fa2009-05-07 18:46:18 +00001469 //
1470 // make sure all the memory allocations were sucessful
1471 //
jcarseybeab0fc2011-10-10 17:26:25 +00001472 if (NULL == NewInfo->FullName || NewInfo->FileName == NULL || NewInfo->Info == NULL) {
Jaben Carsey98c16be2014-08-19 21:00:34 +00001473 //
1474 // Free the partially allocated new node
1475 //
1476 SHELL_FREE_NON_NULL(NewInfo->FullName);
1477 SHELL_FREE_NON_NULL(NewInfo->FileName);
1478 SHELL_FREE_NON_NULL(NewInfo->Info);
1479 SHELL_FREE_NON_NULL(NewInfo);
1480
1481 //
1482 // Free the previously converted stuff
1483 //
jcarsey7a95efd2011-10-13 16:08:18 +00001484 ShellCloseFileMetaArg((EFI_SHELL_FILE_INFO**)(&ListHead));
jcarseybeab0fc2011-10-10 17:26:25 +00001485 ListHead = NULL;
1486 break;
1487 }
jcarsey94b17fa2009-05-07 18:46:18 +00001488
1489 //
jcarsey94b17fa2009-05-07 18:46:18 +00001490 // add that to the list
1491 //
jcarsey9b3bf082009-06-23 21:15:07 +00001492 InsertTailList(ListHead, &NewInfo->Link);
jcarsey94b17fa2009-05-07 18:46:18 +00001493 }
1494 return (ListHead);
1495}
1496/**
1497 Opens a group of files based on a path.
1498
jcarsey1e6e84c2010-01-25 20:05:08 +00001499 This function uses the Arg to open all the matching files. Each matched
Brendan Jackman70879312014-01-24 22:29:53 +00001500 file has a SHELL_FILE_INFO structure to record the file information. These
1501 structures are placed on the list ListHead. Users can get the SHELL_FILE_INFO
jcarsey94b17fa2009-05-07 18:46:18 +00001502 structures from ListHead to access each file. This function supports wildcards
jcarsey1e6e84c2010-01-25 20:05:08 +00001503 and will process '?' and '*' as such. the list must be freed with a call to
jcarsey94b17fa2009-05-07 18:46:18 +00001504 ShellCloseFileMetaArg().
1505
jcarsey1e6e84c2010-01-25 20:05:08 +00001506 If you are NOT appending to an existing list *ListHead must be NULL. If
jcarsey5f7431d2009-07-10 18:06:01 +00001507 *ListHead is NULL then it must be callee freed.
jcarsey94b17fa2009-05-07 18:46:18 +00001508
1509 @param Arg pointer to path string
1510 @param OpenMode mode to open files with
1511 @param ListHead head of linked list of results
1512
jcarsey1e6e84c2010-01-25 20:05:08 +00001513 @retval EFI_SUCCESS the operation was sucessful and the list head
jcarsey94b17fa2009-05-07 18:46:18 +00001514 contains the list of opened files
jcarsey94b17fa2009-05-07 18:46:18 +00001515 @return != EFI_SUCCESS the operation failed
1516
1517 @sa InternalShellConvertFileListType
1518**/
1519EFI_STATUS
1520EFIAPI
1521ShellOpenFileMetaArg (
1522 IN CHAR16 *Arg,
1523 IN UINT64 OpenMode,
1524 IN OUT EFI_SHELL_FILE_INFO **ListHead
1525 )
1526{
1527 EFI_STATUS Status;
jcarsey9b3bf082009-06-23 21:15:07 +00001528 LIST_ENTRY mOldStyleFileList;
Qiu Shumin0960ba12014-09-17 07:58:31 +00001529 CHAR16 *CleanFilePathStr;
jcarsey1e6e84c2010-01-25 20:05:08 +00001530
jcarsey94b17fa2009-05-07 18:46:18 +00001531 //
1532 // ASSERT that Arg and ListHead are not NULL
1533 //
1534 ASSERT(Arg != NULL);
1535 ASSERT(ListHead != NULL);
1536
Qiu Shumin715096c2014-09-19 01:32:05 +00001537 CleanFilePathStr = NULL;
1538
Qiu Shumin0960ba12014-09-17 07:58:31 +00001539 Status = InternalShellStripQuotes (Arg, &CleanFilePathStr);
1540 if (EFI_ERROR (Status)) {
1541 return Status;
1542 }
1543
jcarsey1e6e84c2010-01-25 20:05:08 +00001544 //
jcarsey94b17fa2009-05-07 18:46:18 +00001545 // Check for UEFI Shell 2.0 protocols
1546 //
jcarsey366f81a2011-06-27 21:04:22 +00001547 if (gEfiShellProtocol != NULL) {
jcarsey5f7431d2009-07-10 18:06:01 +00001548 if (*ListHead == NULL) {
1549 *ListHead = (EFI_SHELL_FILE_INFO*)AllocateZeroPool(sizeof(EFI_SHELL_FILE_INFO));
1550 if (*ListHead == NULL) {
Qiu Shumin0960ba12014-09-17 07:58:31 +00001551 FreePool(CleanFilePathStr);
jcarsey5f7431d2009-07-10 18:06:01 +00001552 return (EFI_OUT_OF_RESOURCES);
1553 }
1554 InitializeListHead(&((*ListHead)->Link));
jcarsey1e6e84c2010-01-25 20:05:08 +00001555 }
Qiu Shumin0960ba12014-09-17 07:58:31 +00001556 Status = gEfiShellProtocol->OpenFileList(CleanFilePathStr,
jcarsey1e6e84c2010-01-25 20:05:08 +00001557 OpenMode,
jcarsey2247dde2009-11-09 18:08:58 +00001558 ListHead);
1559 if (EFI_ERROR(Status)) {
jcarsey366f81a2011-06-27 21:04:22 +00001560 gEfiShellProtocol->RemoveDupInFileList(ListHead);
jcarsey2247dde2009-11-09 18:08:58 +00001561 } else {
jcarsey366f81a2011-06-27 21:04:22 +00001562 Status = gEfiShellProtocol->RemoveDupInFileList(ListHead);
jcarsey2247dde2009-11-09 18:08:58 +00001563 }
jcarseya405b862010-09-14 05:18:09 +00001564 if (*ListHead != NULL && IsListEmpty(&(*ListHead)->Link)) {
1565 FreePool(*ListHead);
Qiu Shumin0960ba12014-09-17 07:58:31 +00001566 FreePool(CleanFilePathStr);
jcarseya405b862010-09-14 05:18:09 +00001567 *ListHead = NULL;
1568 return (EFI_NOT_FOUND);
1569 }
Qiu Shumin0960ba12014-09-17 07:58:31 +00001570 FreePool(CleanFilePathStr);
jcarsey2247dde2009-11-09 18:08:58 +00001571 return (Status);
jcarsey1e6e84c2010-01-25 20:05:08 +00001572 }
jcarsey94b17fa2009-05-07 18:46:18 +00001573
1574 //
jcarsey92a54472011-06-27 20:33:13 +00001575 // Check for EFI shell
jcarsey94b17fa2009-05-07 18:46:18 +00001576 //
jcarsey92a54472011-06-27 20:33:13 +00001577 if (mEfiShellEnvironment2 != NULL) {
1578 //
1579 // make sure the list head is initialized
1580 //
1581 InitializeListHead(&mOldStyleFileList);
jcarsey94b17fa2009-05-07 18:46:18 +00001582
jcarsey92a54472011-06-27 20:33:13 +00001583 //
1584 // Get the EFI Shell list of files
1585 //
Qiu Shumin0960ba12014-09-17 07:58:31 +00001586 Status = mEfiShellEnvironment2->FileMetaArg(CleanFilePathStr, &mOldStyleFileList);
jcarsey92a54472011-06-27 20:33:13 +00001587 if (EFI_ERROR(Status)) {
1588 *ListHead = NULL;
Qiu Shumin0960ba12014-09-17 07:58:31 +00001589 FreePool(CleanFilePathStr);
jcarsey92a54472011-06-27 20:33:13 +00001590 return (Status);
1591 }
jcarsey94b17fa2009-05-07 18:46:18 +00001592
jcarsey92a54472011-06-27 20:33:13 +00001593 if (*ListHead == NULL) {
1594 *ListHead = (EFI_SHELL_FILE_INFO *)AllocateZeroPool(sizeof(EFI_SHELL_FILE_INFO));
1595 if (*ListHead == NULL) {
Qiu Shumin0960ba12014-09-17 07:58:31 +00001596 FreePool(CleanFilePathStr);
jcarsey92a54472011-06-27 20:33:13 +00001597 return (EFI_OUT_OF_RESOURCES);
1598 }
1599 InitializeListHead(&((*ListHead)->Link));
1600 }
1601
1602 //
1603 // Convert that to equivalent of UEFI Shell 2.0 structure
1604 //
1605 InternalShellConvertFileListType(&mOldStyleFileList, &(*ListHead)->Link);
1606
1607 //
1608 // Free the EFI Shell version that was converted.
1609 //
1610 mEfiShellEnvironment2->FreeFileList(&mOldStyleFileList);
1611
1612 if ((*ListHead)->Link.ForwardLink == (*ListHead)->Link.BackLink && (*ListHead)->Link.BackLink == &((*ListHead)->Link)) {
1613 FreePool(*ListHead);
1614 *ListHead = NULL;
1615 Status = EFI_NOT_FOUND;
1616 }
Qiu Shumin0960ba12014-09-17 07:58:31 +00001617 FreePool(CleanFilePathStr);
jcarsey94b17fa2009-05-07 18:46:18 +00001618 return (Status);
1619 }
1620
Qiu Shumin0960ba12014-09-17 07:58:31 +00001621 FreePool(CleanFilePathStr);
jcarsey92a54472011-06-27 20:33:13 +00001622 return (EFI_UNSUPPORTED);
jcarsey94b17fa2009-05-07 18:46:18 +00001623}
1624/**
jcarseya405b862010-09-14 05:18:09 +00001625 Free the linked list returned from ShellOpenFileMetaArg.
jcarsey94b17fa2009-05-07 18:46:18 +00001626
jcarseya405b862010-09-14 05:18:09 +00001627 if ListHead is NULL then ASSERT().
jcarsey94b17fa2009-05-07 18:46:18 +00001628
jcarseya405b862010-09-14 05:18:09 +00001629 @param ListHead the pointer to free.
jcarsey94b17fa2009-05-07 18:46:18 +00001630
jcarseya405b862010-09-14 05:18:09 +00001631 @retval EFI_SUCCESS the operation was sucessful.
jcarsey94b17fa2009-05-07 18:46:18 +00001632**/
1633EFI_STATUS
1634EFIAPI
1635ShellCloseFileMetaArg (
1636 IN OUT EFI_SHELL_FILE_INFO **ListHead
1637 )
1638{
1639 LIST_ENTRY *Node;
1640
1641 //
1642 // ASSERT that ListHead is not NULL
1643 //
1644 ASSERT(ListHead != NULL);
1645
jcarsey1e6e84c2010-01-25 20:05:08 +00001646 //
jcarsey94b17fa2009-05-07 18:46:18 +00001647 // Check for UEFI Shell 2.0 protocols
1648 //
jcarsey366f81a2011-06-27 21:04:22 +00001649 if (gEfiShellProtocol != NULL) {
1650 return (gEfiShellProtocol->FreeFileList(ListHead));
jcarsey92a54472011-06-27 20:33:13 +00001651 } else if (mEfiShellEnvironment2 != NULL) {
jcarsey94b17fa2009-05-07 18:46:18 +00001652 //
jcarsey1e6e84c2010-01-25 20:05:08 +00001653 // Since this is EFI Shell version we need to free our internally made copy
jcarsey94b17fa2009-05-07 18:46:18 +00001654 // of the list
1655 //
jcarsey1e6e84c2010-01-25 20:05:08 +00001656 for ( Node = GetFirstNode(&(*ListHead)->Link)
jcarseya405b862010-09-14 05:18:09 +00001657 ; *ListHead != NULL && !IsListEmpty(&(*ListHead)->Link)
jcarsey9b3bf082009-06-23 21:15:07 +00001658 ; Node = GetFirstNode(&(*ListHead)->Link)) {
jcarsey94b17fa2009-05-07 18:46:18 +00001659 RemoveEntryList(Node);
jcarseya405b862010-09-14 05:18:09 +00001660 ((EFI_FILE_PROTOCOL*)((EFI_SHELL_FILE_INFO_NO_CONST*)Node)->Handle)->Close(((EFI_SHELL_FILE_INFO_NO_CONST*)Node)->Handle);
jcarsey94b17fa2009-05-07 18:46:18 +00001661 FreePool(((EFI_SHELL_FILE_INFO_NO_CONST*)Node)->FullName);
1662 FreePool(((EFI_SHELL_FILE_INFO_NO_CONST*)Node)->FileName);
1663 FreePool(((EFI_SHELL_FILE_INFO_NO_CONST*)Node)->Info);
1664 FreePool((EFI_SHELL_FILE_INFO_NO_CONST*)Node);
1665 }
Jaben Carsey75a5e2e2014-01-10 16:42:45 +00001666 SHELL_FREE_NON_NULL(*ListHead);
jcarsey94b17fa2009-05-07 18:46:18 +00001667 return EFI_SUCCESS;
1668 }
jcarsey92a54472011-06-27 20:33:13 +00001669
1670 return (EFI_UNSUPPORTED);
jcarsey94b17fa2009-05-07 18:46:18 +00001671}
1672
jcarsey125c2cf2009-11-18 21:36:50 +00001673/**
1674 Find a file by searching the CWD and then the path.
1675
jcarseyb3011f42010-01-11 21:49:04 +00001676 If FileName is NULL then ASSERT.
jcarsey125c2cf2009-11-18 21:36:50 +00001677
jcarseyb3011f42010-01-11 21:49:04 +00001678 If the return value is not NULL then the memory must be caller freed.
jcarsey125c2cf2009-11-18 21:36:50 +00001679
1680 @param FileName Filename string.
1681
1682 @retval NULL the file was not found
1683 @return !NULL the full path to the file.
1684**/
1685CHAR16 *
1686EFIAPI
1687ShellFindFilePath (
1688 IN CONST CHAR16 *FileName
1689 )
1690{
1691 CONST CHAR16 *Path;
jcarseya405b862010-09-14 05:18:09 +00001692 SHELL_FILE_HANDLE Handle;
jcarsey125c2cf2009-11-18 21:36:50 +00001693 EFI_STATUS Status;
1694 CHAR16 *RetVal;
1695 CHAR16 *TestPath;
1696 CONST CHAR16 *Walker;
jcarsey36a9d672009-11-20 21:13:41 +00001697 UINTN Size;
jcarsey1cd45e72010-01-29 15:07:44 +00001698 CHAR16 *TempChar;
jcarsey125c2cf2009-11-18 21:36:50 +00001699
1700 RetVal = NULL;
1701
jcarseya405b862010-09-14 05:18:09 +00001702 //
1703 // First make sure its not an absolute path.
1704 //
1705 Status = ShellOpenFileByName(FileName, &Handle, EFI_FILE_MODE_READ, 0);
1706 if (!EFI_ERROR(Status)){
1707 if (FileHandleIsDirectory(Handle) != EFI_SUCCESS) {
1708 ASSERT(RetVal == NULL);
1709 RetVal = StrnCatGrow(&RetVal, NULL, FileName, 0);
1710 ShellCloseFile(&Handle);
1711 return (RetVal);
1712 } else {
1713 ShellCloseFile(&Handle);
1714 }
1715 }
1716
jcarsey125c2cf2009-11-18 21:36:50 +00001717 Path = ShellGetEnvironmentVariable(L"cwd");
1718 if (Path != NULL) {
Qiu Shuminfbd2dfa2015-10-23 02:03:20 +00001719 Size = StrSize(Path) + sizeof(CHAR16);
jcarsey36a9d672009-11-20 21:13:41 +00001720 Size += StrSize(FileName);
1721 TestPath = AllocateZeroPool(Size);
jcarseyc9d92df2010-02-03 15:37:54 +00001722 if (TestPath == NULL) {
1723 return (NULL);
1724 }
Qiu Shumine75390f2015-06-30 03:18:31 +00001725 StrCpyS(TestPath, Size/sizeof(CHAR16), Path);
Qiu Shuminfbd2dfa2015-10-23 02:03:20 +00001726 StrCatS(TestPath, Size/sizeof(CHAR16), L"\\");
Qiu Shumine75390f2015-06-30 03:18:31 +00001727 StrCatS(TestPath, Size/sizeof(CHAR16), FileName);
jcarsey125c2cf2009-11-18 21:36:50 +00001728 Status = ShellOpenFileByName(TestPath, &Handle, EFI_FILE_MODE_READ, 0);
1729 if (!EFI_ERROR(Status)){
jcarseya405b862010-09-14 05:18:09 +00001730 if (FileHandleIsDirectory(Handle) != EFI_SUCCESS) {
1731 ASSERT(RetVal == NULL);
1732 RetVal = StrnCatGrow(&RetVal, NULL, TestPath, 0);
1733 ShellCloseFile(&Handle);
1734 FreePool(TestPath);
1735 return (RetVal);
1736 } else {
1737 ShellCloseFile(&Handle);
1738 }
jcarsey125c2cf2009-11-18 21:36:50 +00001739 }
1740 FreePool(TestPath);
1741 }
1742 Path = ShellGetEnvironmentVariable(L"path");
1743 if (Path != NULL) {
jcarseya405b862010-09-14 05:18:09 +00001744 Size = StrSize(Path)+sizeof(CHAR16);
jcarsey36a9d672009-11-20 21:13:41 +00001745 Size += StrSize(FileName);
1746 TestPath = AllocateZeroPool(Size);
jcarsey3e082d52010-10-04 16:44:57 +00001747 if (TestPath == NULL) {
1748 return (NULL);
1749 }
jcarsey1e6e84c2010-01-25 20:05:08 +00001750 Walker = (CHAR16*)Path;
jcarsey125c2cf2009-11-18 21:36:50 +00001751 do {
1752 CopyMem(TestPath, Walker, StrSize(Walker));
jcarsey3e082d52010-10-04 16:44:57 +00001753 if (TestPath != NULL) {
1754 TempChar = StrStr(TestPath, L";");
1755 if (TempChar != NULL) {
1756 *TempChar = CHAR_NULL;
1757 }
1758 if (TestPath[StrLen(TestPath)-1] != L'\\') {
Qiu Shumine75390f2015-06-30 03:18:31 +00001759 StrCatS(TestPath, Size/sizeof(CHAR16), L"\\");
jcarsey3e082d52010-10-04 16:44:57 +00001760 }
jcarsey89e85372011-04-13 23:37:50 +00001761 if (FileName[0] == L'\\') {
1762 FileName++;
1763 }
Qiu Shumine75390f2015-06-30 03:18:31 +00001764 StrCatS(TestPath, Size/sizeof(CHAR16), FileName);
jcarsey3e082d52010-10-04 16:44:57 +00001765 if (StrStr(Walker, L";") != NULL) {
1766 Walker = StrStr(Walker, L";") + 1;
jcarseya405b862010-09-14 05:18:09 +00001767 } else {
jcarsey3e082d52010-10-04 16:44:57 +00001768 Walker = NULL;
1769 }
1770 Status = ShellOpenFileByName(TestPath, &Handle, EFI_FILE_MODE_READ, 0);
1771 if (!EFI_ERROR(Status)){
1772 if (FileHandleIsDirectory(Handle) != EFI_SUCCESS) {
1773 ASSERT(RetVal == NULL);
1774 RetVal = StrnCatGrow(&RetVal, NULL, TestPath, 0);
1775 ShellCloseFile(&Handle);
1776 break;
1777 } else {
1778 ShellCloseFile(&Handle);
1779 }
jcarseya405b862010-09-14 05:18:09 +00001780 }
jcarsey125c2cf2009-11-18 21:36:50 +00001781 }
1782 } while (Walker != NULL && Walker[0] != CHAR_NULL);
1783 FreePool(TestPath);
1784 }
1785 return (RetVal);
1786}
1787
jcarseyb3011f42010-01-11 21:49:04 +00001788/**
jcarsey1e6e84c2010-01-25 20:05:08 +00001789 Find a file by searching the CWD and then the path with a variable set of file
1790 extensions. If the file is not found it will append each extension in the list
jcarseyb3011f42010-01-11 21:49:04 +00001791 in the order provided and return the first one that is successful.
1792
1793 If FileName is NULL, then ASSERT.
1794 If FileExtension is NULL, then behavior is identical to ShellFindFilePath.
1795
1796 If the return value is not NULL then the memory must be caller freed.
1797
1798 @param[in] FileName Filename string.
1799 @param[in] FileExtension Semi-colon delimeted list of possible extensions.
1800
1801 @retval NULL The file was not found.
1802 @retval !NULL The path to the file.
1803**/
1804CHAR16 *
1805EFIAPI
1806ShellFindFilePathEx (
1807 IN CONST CHAR16 *FileName,
1808 IN CONST CHAR16 *FileExtension
1809 )
1810{
1811 CHAR16 *TestPath;
1812 CHAR16 *RetVal;
1813 CONST CHAR16 *ExtensionWalker;
jcarsey9e926b62010-01-14 20:26:39 +00001814 UINTN Size;
jcarsey1cd45e72010-01-29 15:07:44 +00001815 CHAR16 *TempChar;
jcarseyc9d92df2010-02-03 15:37:54 +00001816 CHAR16 *TempChar2;
jcarsey1cd45e72010-01-29 15:07:44 +00001817
jcarseyb3011f42010-01-11 21:49:04 +00001818 ASSERT(FileName != NULL);
1819 if (FileExtension == NULL) {
1820 return (ShellFindFilePath(FileName));
1821 }
1822 RetVal = ShellFindFilePath(FileName);
1823 if (RetVal != NULL) {
1824 return (RetVal);
1825 }
jcarsey9e926b62010-01-14 20:26:39 +00001826 Size = StrSize(FileName);
1827 Size += StrSize(FileExtension);
1828 TestPath = AllocateZeroPool(Size);
jcarseyc9d92df2010-02-03 15:37:54 +00001829 if (TestPath == NULL) {
1830 return (NULL);
1831 }
jcarseya405b862010-09-14 05:18:09 +00001832 for (ExtensionWalker = FileExtension, TempChar2 = (CHAR16*)FileExtension; TempChar2 != NULL ; ExtensionWalker = TempChar2 + 1){
Qiu Shumine75390f2015-06-30 03:18:31 +00001833 StrCpyS(TestPath, Size/sizeof(CHAR16), FileName);
jcarseya405b862010-09-14 05:18:09 +00001834 if (ExtensionWalker != NULL) {
Qiu Shumine75390f2015-06-30 03:18:31 +00001835 StrCatS(TestPath, Size/sizeof(CHAR16), ExtensionWalker);
jcarseya405b862010-09-14 05:18:09 +00001836 }
jcarsey1cd45e72010-01-29 15:07:44 +00001837 TempChar = StrStr(TestPath, L";");
1838 if (TempChar != NULL) {
1839 *TempChar = CHAR_NULL;
jcarseyb3011f42010-01-11 21:49:04 +00001840 }
1841 RetVal = ShellFindFilePath(TestPath);
1842 if (RetVal != NULL) {
1843 break;
1844 }
jcarseya405b862010-09-14 05:18:09 +00001845 ASSERT(ExtensionWalker != NULL);
jcarseyc9d92df2010-02-03 15:37:54 +00001846 TempChar2 = StrStr(ExtensionWalker, L";");
jcarseyb3011f42010-01-11 21:49:04 +00001847 }
1848 FreePool(TestPath);
1849 return (RetVal);
1850}
1851
jcarsey94b17fa2009-05-07 18:46:18 +00001852typedef struct {
jcarsey9b3bf082009-06-23 21:15:07 +00001853 LIST_ENTRY Link;
jcarsey94b17fa2009-05-07 18:46:18 +00001854 CHAR16 *Name;
jcarseya405b862010-09-14 05:18:09 +00001855 SHELL_PARAM_TYPE Type;
jcarsey94b17fa2009-05-07 18:46:18 +00001856 CHAR16 *Value;
1857 UINTN OriginalPosition;
1858} SHELL_PARAM_PACKAGE;
1859
1860/**
jcarsey1e6e84c2010-01-25 20:05:08 +00001861 Checks the list of valid arguments and returns TRUE if the item was found. If the
jcarsey94b17fa2009-05-07 18:46:18 +00001862 return value is TRUE then the type parameter is set also.
jcarsey1e6e84c2010-01-25 20:05:08 +00001863
jcarsey94b17fa2009-05-07 18:46:18 +00001864 if CheckList is NULL then ASSERT();
1865 if Name is NULL then ASSERT();
1866 if Type is NULL then ASSERT();
1867
jcarsey94b17fa2009-05-07 18:46:18 +00001868 @param Name pointer to Name of parameter found
1869 @param CheckList List to check against
jcarseya405b862010-09-14 05:18:09 +00001870 @param Type pointer to type of parameter if it was found
jcarsey94b17fa2009-05-07 18:46:18 +00001871
1872 @retval TRUE the Parameter was found. Type is valid.
1873 @retval FALSE the Parameter was not found. Type is not valid.
1874**/
1875BOOLEAN
1876EFIAPI
jcarseyd2b45642009-05-11 18:02:16 +00001877InternalIsOnCheckList (
jcarsey94b17fa2009-05-07 18:46:18 +00001878 IN CONST CHAR16 *Name,
1879 IN CONST SHELL_PARAM_ITEM *CheckList,
jcarsey252d9452011-03-25 20:49:53 +00001880 OUT SHELL_PARAM_TYPE *Type
jcarseya405b862010-09-14 05:18:09 +00001881 )
1882{
jcarsey94b17fa2009-05-07 18:46:18 +00001883 SHELL_PARAM_ITEM *TempListItem;
jcarsey252d9452011-03-25 20:49:53 +00001884 CHAR16 *TempString;
jcarsey94b17fa2009-05-07 18:46:18 +00001885
1886 //
1887 // ASSERT that all 3 pointer parameters aren't NULL
1888 //
1889 ASSERT(CheckList != NULL);
1890 ASSERT(Type != NULL);
1891 ASSERT(Name != NULL);
1892
1893 //
jcarseyd2b45642009-05-11 18:02:16 +00001894 // question mark and page break mode are always supported
1895 //
1896 if ((StrCmp(Name, L"-?") == 0) ||
1897 (StrCmp(Name, L"-b") == 0)
jcarseya405b862010-09-14 05:18:09 +00001898 ) {
jcarsey252d9452011-03-25 20:49:53 +00001899 *Type = TypeFlag;
jcarseyd2b45642009-05-11 18:02:16 +00001900 return (TRUE);
1901 }
1902
1903 //
jcarsey94b17fa2009-05-07 18:46:18 +00001904 // Enumerate through the list
1905 //
1906 for (TempListItem = (SHELL_PARAM_ITEM*)CheckList ; TempListItem->Name != NULL ; TempListItem++) {
1907 //
jcarsey9eb53ac2009-07-08 17:26:58 +00001908 // If the Type is TypeStart only check the first characters of the passed in param
1909 // If it matches set the type and return TRUE
jcarsey94b17fa2009-05-07 18:46:18 +00001910 //
darylm503b0934ac2011-11-12 00:35:11 +00001911 if (TempListItem->Type == TypeStart) {
jcarsey252d9452011-03-25 20:49:53 +00001912 if (StrnCmp(Name, TempListItem->Name, StrLen(TempListItem->Name)) == 0) {
1913 *Type = TempListItem->Type;
1914 return (TRUE);
1915 }
1916 TempString = NULL;
1917 TempString = StrnCatGrow(&TempString, NULL, Name, StrLen(TempListItem->Name));
1918 if (TempString != NULL) {
1919 if (StringNoCaseCompare(&TempString, &TempListItem->Name) == 0) {
1920 *Type = TempListItem->Type;
1921 FreePool(TempString);
1922 return (TRUE);
1923 }
1924 FreePool(TempString);
1925 }
1926 } else if (StringNoCaseCompare(&Name, &TempListItem->Name) == 0) {
jcarsey94b17fa2009-05-07 18:46:18 +00001927 *Type = TempListItem->Type;
1928 return (TRUE);
1929 }
1930 }
jcarsey2247dde2009-11-09 18:08:58 +00001931
jcarsey94b17fa2009-05-07 18:46:18 +00001932 return (FALSE);
1933}
1934/**
jcarseyd2b45642009-05-11 18:02:16 +00001935 Checks the string for indicators of "flag" status. this is a leading '/', '-', or '+'
jcarsey94b17fa2009-05-07 18:46:18 +00001936
jcarseya405b862010-09-14 05:18:09 +00001937 @param[in] Name pointer to Name of parameter found
1938 @param[in] AlwaysAllowNumbers TRUE to allow numbers, FALSE to not.
jcarsey658bf432014-11-04 22:33:16 +00001939 @param[in] TimeNumbers TRUE to allow numbers with ":", FALSE otherwise.
jcarsey94b17fa2009-05-07 18:46:18 +00001940
1941 @retval TRUE the Parameter is a flag.
jcarseya405b862010-09-14 05:18:09 +00001942 @retval FALSE the Parameter not a flag.
jcarsey94b17fa2009-05-07 18:46:18 +00001943**/
1944BOOLEAN
1945EFIAPI
jcarseyd2b45642009-05-11 18:02:16 +00001946InternalIsFlag (
jcarsey2247dde2009-11-09 18:08:58 +00001947 IN CONST CHAR16 *Name,
jcarsey658bf432014-11-04 22:33:16 +00001948 IN CONST BOOLEAN AlwaysAllowNumbers,
1949 IN CONST BOOLEAN TimeNumbers
jcarsey94b17fa2009-05-07 18:46:18 +00001950 )
1951{
1952 //
1953 // ASSERT that Name isn't NULL
1954 //
1955 ASSERT(Name != NULL);
1956
1957 //
jcarsey2247dde2009-11-09 18:08:58 +00001958 // If we accept numbers then dont return TRUE. (they will be values)
1959 //
jcarsey658bf432014-11-04 22:33:16 +00001960 if (((Name[0] == L'-' || Name[0] == L'+') && InternalShellIsHexOrDecimalNumber(Name+1, FALSE, FALSE, TimeNumbers)) && AlwaysAllowNumbers) {
jcarsey2247dde2009-11-09 18:08:58 +00001961 return (FALSE);
1962 }
1963
1964 //
jcarseya405b862010-09-14 05:18:09 +00001965 // If the Name has a /, +, or - as the first character return TRUE
jcarsey94b17fa2009-05-07 18:46:18 +00001966 //
jcarsey1e6e84c2010-01-25 20:05:08 +00001967 if ((Name[0] == L'/') ||
jcarseyd2b45642009-05-11 18:02:16 +00001968 (Name[0] == L'-') ||
1969 (Name[0] == L'+')
jcarseya405b862010-09-14 05:18:09 +00001970 ) {
jcarsey94b17fa2009-05-07 18:46:18 +00001971 return (TRUE);
1972 }
1973 return (FALSE);
1974}
1975
1976/**
jcarsey1e6e84c2010-01-25 20:05:08 +00001977 Checks the command line arguments passed against the list of valid ones.
jcarsey94b17fa2009-05-07 18:46:18 +00001978
1979 If no initialization is required, then return RETURN_SUCCESS.
jcarsey1e6e84c2010-01-25 20:05:08 +00001980
jcarseya405b862010-09-14 05:18:09 +00001981 @param[in] CheckList pointer to list of parameters to check
1982 @param[out] CheckPackage pointer to pointer to list checked values
1983 @param[out] ProblemParam optional pointer to pointer to unicode string for
jcarseyd2b45642009-05-11 18:02:16 +00001984 the paramater that caused failure. If used then the
1985 caller is responsible for freeing the memory.
jcarseya405b862010-09-14 05:18:09 +00001986 @param[in] AutoPageBreak will automatically set PageBreakEnabled for "b" parameter
1987 @param[in] Argv pointer to array of parameters
1988 @param[in] Argc Count of parameters in Argv
1989 @param[in] AlwaysAllowNumbers TRUE to allow numbers always, FALSE otherwise.
jcarsey94b17fa2009-05-07 18:46:18 +00001990
1991 @retval EFI_SUCCESS The operation completed sucessfully.
1992 @retval EFI_OUT_OF_RESOURCES A memory allocation failed
1993 @retval EFI_INVALID_PARAMETER A parameter was invalid
jcarsey1e6e84c2010-01-25 20:05:08 +00001994 @retval EFI_VOLUME_CORRUPTED the command line was corrupt. an argument was
1995 duplicated. the duplicated command line argument
jcarsey94b17fa2009-05-07 18:46:18 +00001996 was returned in ProblemParam if provided.
jcarsey1e6e84c2010-01-25 20:05:08 +00001997 @retval EFI_NOT_FOUND a argument required a value that was missing.
jcarsey94b17fa2009-05-07 18:46:18 +00001998 the invalid command line argument was returned in
1999 ProblemParam if provided.
2000**/
2001EFI_STATUS
2002EFIAPI
2003InternalCommandLineParse (
2004 IN CONST SHELL_PARAM_ITEM *CheckList,
2005 OUT LIST_ENTRY **CheckPackage,
2006 OUT CHAR16 **ProblemParam OPTIONAL,
2007 IN BOOLEAN AutoPageBreak,
2008 IN CONST CHAR16 **Argv,
jcarsey2247dde2009-11-09 18:08:58 +00002009 IN UINTN Argc,
2010 IN BOOLEAN AlwaysAllowNumbers
jcarseya405b862010-09-14 05:18:09 +00002011 )
2012{
jcarsey94b17fa2009-05-07 18:46:18 +00002013 UINTN LoopCounter;
jcarsey252d9452011-03-25 20:49:53 +00002014 SHELL_PARAM_TYPE CurrentItemType;
jcarsey94b17fa2009-05-07 18:46:18 +00002015 SHELL_PARAM_PACKAGE *CurrentItemPackage;
jcarsey125c2cf2009-11-18 21:36:50 +00002016 UINTN GetItemValue;
2017 UINTN ValueSize;
jcarseya405b862010-09-14 05:18:09 +00002018 UINTN Count;
jcarsey252d9452011-03-25 20:49:53 +00002019 CONST CHAR16 *TempPointer;
Jaben Carsey98c16be2014-08-19 21:00:34 +00002020 UINTN CurrentValueSize;
jcarsey94b17fa2009-05-07 18:46:18 +00002021
2022 CurrentItemPackage = NULL;
jcarsey125c2cf2009-11-18 21:36:50 +00002023 GetItemValue = 0;
2024 ValueSize = 0;
jcarseya405b862010-09-14 05:18:09 +00002025 Count = 0;
jcarsey94b17fa2009-05-07 18:46:18 +00002026
2027 //
2028 // If there is only 1 item we dont need to do anything
2029 //
jcarseya405b862010-09-14 05:18:09 +00002030 if (Argc < 1) {
jcarsey94b17fa2009-05-07 18:46:18 +00002031 *CheckPackage = NULL;
2032 return (EFI_SUCCESS);
2033 }
2034
2035 //
jcarsey2247dde2009-11-09 18:08:58 +00002036 // ASSERTs
2037 //
2038 ASSERT(CheckList != NULL);
2039 ASSERT(Argv != NULL);
2040
2041 //
jcarsey94b17fa2009-05-07 18:46:18 +00002042 // initialize the linked list
2043 //
2044 *CheckPackage = (LIST_ENTRY*)AllocateZeroPool(sizeof(LIST_ENTRY));
sfu502a758c2011-10-08 02:55:30 +00002045 if (*CheckPackage == NULL) {
jcarseybeab0fc2011-10-10 17:26:25 +00002046 return (EFI_OUT_OF_RESOURCES);
sfu502a758c2011-10-08 02:55:30 +00002047 }
jcarseybeab0fc2011-10-10 17:26:25 +00002048
jcarsey94b17fa2009-05-07 18:46:18 +00002049 InitializeListHead(*CheckPackage);
2050
2051 //
2052 // loop through each of the arguments
2053 //
2054 for (LoopCounter = 0 ; LoopCounter < Argc ; ++LoopCounter) {
2055 if (Argv[LoopCounter] == NULL) {
2056 //
2057 // do nothing for NULL argv
2058 //
jcarseya405b862010-09-14 05:18:09 +00002059 } else if (InternalIsOnCheckList(Argv[LoopCounter], CheckList, &CurrentItemType)) {
jcarsey94b17fa2009-05-07 18:46:18 +00002060 //
jcarsey2247dde2009-11-09 18:08:58 +00002061 // We might have leftover if last parameter didnt have optional value
2062 //
jcarsey125c2cf2009-11-18 21:36:50 +00002063 if (GetItemValue != 0) {
2064 GetItemValue = 0;
jcarsey2247dde2009-11-09 18:08:58 +00002065 InsertHeadList(*CheckPackage, &CurrentItemPackage->Link);
2066 }
2067 //
jcarsey94b17fa2009-05-07 18:46:18 +00002068 // this is a flag
2069 //
jcarsey252d9452011-03-25 20:49:53 +00002070 CurrentItemPackage = AllocateZeroPool(sizeof(SHELL_PARAM_PACKAGE));
jcarseybeab0fc2011-10-10 17:26:25 +00002071 if (CurrentItemPackage == NULL) {
2072 ShellCommandLineFreeVarList(*CheckPackage);
2073 *CheckPackage = NULL;
2074 return (EFI_OUT_OF_RESOURCES);
2075 }
Jaben Carsey98c16be2014-08-19 21:00:34 +00002076 CurrentItemPackage->Name = AllocateCopyPool(StrSize(Argv[LoopCounter]), Argv[LoopCounter]);
jcarseybeab0fc2011-10-10 17:26:25 +00002077 if (CurrentItemPackage->Name == NULL) {
2078 ShellCommandLineFreeVarList(*CheckPackage);
2079 *CheckPackage = NULL;
2080 return (EFI_OUT_OF_RESOURCES);
2081 }
jcarsey94b17fa2009-05-07 18:46:18 +00002082 CurrentItemPackage->Type = CurrentItemType;
2083 CurrentItemPackage->OriginalPosition = (UINTN)(-1);
jcarseyb1f95a02009-06-16 00:23:19 +00002084 CurrentItemPackage->Value = NULL;
jcarsey94b17fa2009-05-07 18:46:18 +00002085
2086 //
2087 // Does this flag require a value
2088 //
jcarsey125c2cf2009-11-18 21:36:50 +00002089 switch (CurrentItemPackage->Type) {
jcarsey94b17fa2009-05-07 18:46:18 +00002090 //
jcarsey125c2cf2009-11-18 21:36:50 +00002091 // possibly trigger the next loop(s) to populate the value of this item
jcarsey1e6e84c2010-01-25 20:05:08 +00002092 //
jcarsey125c2cf2009-11-18 21:36:50 +00002093 case TypeValue:
jcarsey658bf432014-11-04 22:33:16 +00002094 case TypeTimeValue:
jcarsey1e6e84c2010-01-25 20:05:08 +00002095 GetItemValue = 1;
jcarsey125c2cf2009-11-18 21:36:50 +00002096 ValueSize = 0;
2097 break;
2098 case TypeDoubleValue:
2099 GetItemValue = 2;
2100 ValueSize = 0;
2101 break;
2102 case TypeMaxValue:
2103 GetItemValue = (UINTN)(-1);
2104 ValueSize = 0;
2105 break;
2106 default:
2107 //
2108 // this item has no value expected; we are done
2109 //
2110 InsertHeadList(*CheckPackage, &CurrentItemPackage->Link);
2111 ASSERT(GetItemValue == 0);
2112 break;
jcarsey94b17fa2009-05-07 18:46:18 +00002113 }
Qiu Shuminaf7a3a52015-03-13 02:04:17 +00002114 } else if (GetItemValue != 0 && CurrentItemPackage != NULL && !InternalIsFlag(Argv[LoopCounter], AlwaysAllowNumbers, (BOOLEAN)(CurrentItemPackage->Type == TypeTimeValue))) {
jcarseyb1f95a02009-06-16 00:23:19 +00002115 //
jcarsey125c2cf2009-11-18 21:36:50 +00002116 // get the item VALUE for a previous flag
jcarseyb1f95a02009-06-16 00:23:19 +00002117 //
Qiu Shumin484dd082015-04-01 00:49:05 +00002118 CurrentValueSize = ValueSize + StrSize(Argv[LoopCounter]) + sizeof(CHAR16);
2119 CurrentItemPackage->Value = ReallocatePool(ValueSize, CurrentValueSize, CurrentItemPackage->Value);
2120 ASSERT(CurrentItemPackage->Value != NULL);
2121 if (ValueSize == 0) {
Qiu Shumine75390f2015-06-30 03:18:31 +00002122 StrCpyS( CurrentItemPackage->Value,
2123 CurrentValueSize/sizeof(CHAR16),
2124 Argv[LoopCounter]
2125 );
jcarsey125c2cf2009-11-18 21:36:50 +00002126 } else {
Qiu Shumine75390f2015-06-30 03:18:31 +00002127 StrCatS( CurrentItemPackage->Value,
2128 CurrentValueSize/sizeof(CHAR16),
2129 L" "
2130 );
2131 StrCatS( CurrentItemPackage->Value,
2132 CurrentValueSize/sizeof(CHAR16),
2133 Argv[LoopCounter]
2134 );
jcarsey125c2cf2009-11-18 21:36:50 +00002135 }
Qiu Shumin484dd082015-04-01 00:49:05 +00002136 ValueSize += StrSize(Argv[LoopCounter]) + sizeof(CHAR16);
2137
jcarsey125c2cf2009-11-18 21:36:50 +00002138 GetItemValue--;
2139 if (GetItemValue == 0) {
2140 InsertHeadList(*CheckPackage, &CurrentItemPackage->Link);
2141 }
jcarsey658bf432014-11-04 22:33:16 +00002142 } else if (!InternalIsFlag(Argv[LoopCounter], AlwaysAllowNumbers, FALSE)){
jcarseyb1f95a02009-06-16 00:23:19 +00002143 //
2144 // add this one as a non-flag
2145 //
jcarsey252d9452011-03-25 20:49:53 +00002146
2147 TempPointer = Argv[LoopCounter];
darylm503b0934ac2011-11-12 00:35:11 +00002148 if ((*TempPointer == L'^' && *(TempPointer+1) == L'-')
jcarsey252d9452011-03-25 20:49:53 +00002149 || (*TempPointer == L'^' && *(TempPointer+1) == L'/')
2150 || (*TempPointer == L'^' && *(TempPointer+1) == L'+')
2151 ){
2152 TempPointer++;
2153 }
2154 CurrentItemPackage = AllocateZeroPool(sizeof(SHELL_PARAM_PACKAGE));
jcarseybeab0fc2011-10-10 17:26:25 +00002155 if (CurrentItemPackage == NULL) {
2156 ShellCommandLineFreeVarList(*CheckPackage);
2157 *CheckPackage = NULL;
2158 return (EFI_OUT_OF_RESOURCES);
2159 }
jcarseyb1f95a02009-06-16 00:23:19 +00002160 CurrentItemPackage->Name = NULL;
2161 CurrentItemPackage->Type = TypePosition;
Jaben Carsey98c16be2014-08-19 21:00:34 +00002162 CurrentItemPackage->Value = AllocateCopyPool(StrSize(TempPointer), TempPointer);
jcarseybeab0fc2011-10-10 17:26:25 +00002163 if (CurrentItemPackage->Value == NULL) {
2164 ShellCommandLineFreeVarList(*CheckPackage);
2165 *CheckPackage = NULL;
2166 return (EFI_OUT_OF_RESOURCES);
2167 }
jcarseya405b862010-09-14 05:18:09 +00002168 CurrentItemPackage->OriginalPosition = Count++;
jcarsey9b3bf082009-06-23 21:15:07 +00002169 InsertHeadList(*CheckPackage, &CurrentItemPackage->Link);
jcarsey252d9452011-03-25 20:49:53 +00002170 } else {
jcarsey94b17fa2009-05-07 18:46:18 +00002171 //
2172 // this was a non-recognised flag... error!
2173 //
jcarsey252d9452011-03-25 20:49:53 +00002174 if (ProblemParam != NULL) {
Jaben Carsey98c16be2014-08-19 21:00:34 +00002175 *ProblemParam = AllocateCopyPool(StrSize(Argv[LoopCounter]), Argv[LoopCounter]);
jcarsey252d9452011-03-25 20:49:53 +00002176 }
jcarsey94b17fa2009-05-07 18:46:18 +00002177 ShellCommandLineFreeVarList(*CheckPackage);
2178 *CheckPackage = NULL;
2179 return (EFI_VOLUME_CORRUPTED);
jcarsey94b17fa2009-05-07 18:46:18 +00002180 }
2181 }
jcarsey125c2cf2009-11-18 21:36:50 +00002182 if (GetItemValue != 0) {
2183 GetItemValue = 0;
2184 InsertHeadList(*CheckPackage, &CurrentItemPackage->Link);
2185 }
jcarsey94b17fa2009-05-07 18:46:18 +00002186 //
2187 // support for AutoPageBreak
2188 //
2189 if (AutoPageBreak && ShellCommandLineGetFlag(*CheckPackage, L"-b")) {
2190 ShellSetPageBreakMode(TRUE);
2191 }
2192 return (EFI_SUCCESS);
2193}
2194
2195/**
jcarsey1e6e84c2010-01-25 20:05:08 +00002196 Checks the command line arguments passed against the list of valid ones.
jcarsey94b17fa2009-05-07 18:46:18 +00002197 Optionally removes NULL values first.
jcarsey1e6e84c2010-01-25 20:05:08 +00002198
jcarsey94b17fa2009-05-07 18:46:18 +00002199 If no initialization is required, then return RETURN_SUCCESS.
jcarsey1e6e84c2010-01-25 20:05:08 +00002200
jcarseya405b862010-09-14 05:18:09 +00002201 @param[in] CheckList The pointer to list of parameters to check.
2202 @param[out] CheckPackage The package of checked values.
2203 @param[out] ProblemParam Optional pointer to pointer to unicode string for
jcarsey94b17fa2009-05-07 18:46:18 +00002204 the paramater that caused failure.
jcarseya405b862010-09-14 05:18:09 +00002205 @param[in] AutoPageBreak Will automatically set PageBreakEnabled.
2206 @param[in] AlwaysAllowNumbers Will never fail for number based flags.
jcarsey94b17fa2009-05-07 18:46:18 +00002207
2208 @retval EFI_SUCCESS The operation completed sucessfully.
jcarseya405b862010-09-14 05:18:09 +00002209 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
2210 @retval EFI_INVALID_PARAMETER A parameter was invalid.
2211 @retval EFI_VOLUME_CORRUPTED The command line was corrupt.
2212 @retval EFI_DEVICE_ERROR The commands contained 2 opposing arguments. One
jcarsey1e6e84c2010-01-25 20:05:08 +00002213 of the command line arguments was returned in
jcarsey94b17fa2009-05-07 18:46:18 +00002214 ProblemParam if provided.
jcarseya405b862010-09-14 05:18:09 +00002215 @retval EFI_NOT_FOUND A argument required a value that was missing.
2216 The invalid command line argument was returned in
jcarsey94b17fa2009-05-07 18:46:18 +00002217 ProblemParam if provided.
2218**/
2219EFI_STATUS
2220EFIAPI
jcarsey2247dde2009-11-09 18:08:58 +00002221ShellCommandLineParseEx (
jcarsey94b17fa2009-05-07 18:46:18 +00002222 IN CONST SHELL_PARAM_ITEM *CheckList,
2223 OUT LIST_ENTRY **CheckPackage,
2224 OUT CHAR16 **ProblemParam OPTIONAL,
jcarsey2247dde2009-11-09 18:08:58 +00002225 IN BOOLEAN AutoPageBreak,
2226 IN BOOLEAN AlwaysAllowNumbers
jcarseya405b862010-09-14 05:18:09 +00002227 )
2228{
jcarsey1e6e84c2010-01-25 20:05:08 +00002229 //
jcarsey94b17fa2009-05-07 18:46:18 +00002230 // ASSERT that CheckList and CheckPackage aren't NULL
2231 //
2232 ASSERT(CheckList != NULL);
2233 ASSERT(CheckPackage != NULL);
2234
jcarsey1e6e84c2010-01-25 20:05:08 +00002235 //
jcarsey94b17fa2009-05-07 18:46:18 +00002236 // Check for UEFI Shell 2.0 protocols
2237 //
jcarsey366f81a2011-06-27 21:04:22 +00002238 if (gEfiShellParametersProtocol != NULL) {
jcarsey1e6e84c2010-01-25 20:05:08 +00002239 return (InternalCommandLineParse(CheckList,
2240 CheckPackage,
2241 ProblemParam,
2242 AutoPageBreak,
jcarsey366f81a2011-06-27 21:04:22 +00002243 (CONST CHAR16**) gEfiShellParametersProtocol->Argv,
2244 gEfiShellParametersProtocol->Argc,
jcarsey2247dde2009-11-09 18:08:58 +00002245 AlwaysAllowNumbers));
jcarsey94b17fa2009-05-07 18:46:18 +00002246 }
2247
jcarsey1e6e84c2010-01-25 20:05:08 +00002248 //
jcarsey94b17fa2009-05-07 18:46:18 +00002249 // ASSERT That EFI Shell is not required
2250 //
2251 ASSERT (mEfiShellInterface != NULL);
jcarsey1e6e84c2010-01-25 20:05:08 +00002252 return (InternalCommandLineParse(CheckList,
2253 CheckPackage,
2254 ProblemParam,
2255 AutoPageBreak,
jljusten08d7f8e2009-06-15 18:42:13 +00002256 (CONST CHAR16**) mEfiShellInterface->Argv,
jcarsey2247dde2009-11-09 18:08:58 +00002257 mEfiShellInterface->Argc,
2258 AlwaysAllowNumbers));
jcarsey94b17fa2009-05-07 18:46:18 +00002259}
2260
2261/**
2262 Frees shell variable list that was returned from ShellCommandLineParse.
2263
2264 This function will free all the memory that was used for the CheckPackage
2265 list of postprocessed shell arguments.
2266
2267 this function has no return value.
2268
2269 if CheckPackage is NULL, then return
2270
2271 @param CheckPackage the list to de-allocate
2272 **/
2273VOID
2274EFIAPI
2275ShellCommandLineFreeVarList (
2276 IN LIST_ENTRY *CheckPackage
jcarseya405b862010-09-14 05:18:09 +00002277 )
2278{
jcarsey94b17fa2009-05-07 18:46:18 +00002279 LIST_ENTRY *Node;
2280
2281 //
2282 // check for CheckPackage == NULL
2283 //
2284 if (CheckPackage == NULL) {
2285 return;
2286 }
2287
2288 //
2289 // for each node in the list
2290 //
jcarsey9eb53ac2009-07-08 17:26:58 +00002291 for ( Node = GetFirstNode(CheckPackage)
jcarseya405b862010-09-14 05:18:09 +00002292 ; !IsListEmpty(CheckPackage)
jcarsey9eb53ac2009-07-08 17:26:58 +00002293 ; Node = GetFirstNode(CheckPackage)
jcarseya405b862010-09-14 05:18:09 +00002294 ){
jcarsey94b17fa2009-05-07 18:46:18 +00002295 //
2296 // Remove it from the list
2297 //
2298 RemoveEntryList(Node);
2299
2300 //
2301 // if it has a name free the name
2302 //
2303 if (((SHELL_PARAM_PACKAGE*)Node)->Name != NULL) {
2304 FreePool(((SHELL_PARAM_PACKAGE*)Node)->Name);
2305 }
2306
2307 //
2308 // if it has a value free the value
2309 //
2310 if (((SHELL_PARAM_PACKAGE*)Node)->Value != NULL) {
2311 FreePool(((SHELL_PARAM_PACKAGE*)Node)->Value);
2312 }
jcarsey1e6e84c2010-01-25 20:05:08 +00002313
jcarsey94b17fa2009-05-07 18:46:18 +00002314 //
2315 // free the node structure
2316 //
2317 FreePool((SHELL_PARAM_PACKAGE*)Node);
2318 }
2319 //
2320 // free the list head node
2321 //
2322 FreePool(CheckPackage);
2323}
2324/**
2325 Checks for presence of a flag parameter
2326
2327 flag arguments are in the form of "-<Key>" or "/<Key>", but do not have a value following the key
2328
2329 if CheckPackage is NULL then return FALSE.
2330 if KeyString is NULL then ASSERT()
jcarsey1e6e84c2010-01-25 20:05:08 +00002331
jcarsey94b17fa2009-05-07 18:46:18 +00002332 @param CheckPackage The package of parsed command line arguments
2333 @param KeyString the Key of the command line argument to check for
2334
2335 @retval TRUE the flag is on the command line
2336 @retval FALSE the flag is not on the command line
2337 **/
2338BOOLEAN
2339EFIAPI
2340ShellCommandLineGetFlag (
jcarseya405b862010-09-14 05:18:09 +00002341 IN CONST LIST_ENTRY * CONST CheckPackage,
2342 IN CONST CHAR16 * CONST KeyString
2343 )
2344{
jcarsey94b17fa2009-05-07 18:46:18 +00002345 LIST_ENTRY *Node;
jcarsey252d9452011-03-25 20:49:53 +00002346 CHAR16 *TempString;
jcarsey94b17fa2009-05-07 18:46:18 +00002347
2348 //
ydong100c1950b2011-10-13 02:37:35 +00002349 // return FALSE for no package or KeyString is NULL
jcarsey94b17fa2009-05-07 18:46:18 +00002350 //
ydong100c1950b2011-10-13 02:37:35 +00002351 if (CheckPackage == NULL || KeyString == NULL) {
jcarsey94b17fa2009-05-07 18:46:18 +00002352 return (FALSE);
2353 }
2354
2355 //
2356 // enumerate through the list of parametrs
2357 //
jcarsey1e6e84c2010-01-25 20:05:08 +00002358 for ( Node = GetFirstNode(CheckPackage)
2359 ; !IsNull (CheckPackage, Node)
2360 ; Node = GetNextNode(CheckPackage, Node)
jcarsey252d9452011-03-25 20:49:53 +00002361 ){
jcarsey94b17fa2009-05-07 18:46:18 +00002362 //
2363 // If the Name matches, return TRUE (and there may be NULL name)
2364 //
2365 if (((SHELL_PARAM_PACKAGE*)Node)->Name != NULL) {
jcarsey9eb53ac2009-07-08 17:26:58 +00002366 //
2367 // If Type is TypeStart then only compare the begining of the strings
2368 //
jcarsey252d9452011-03-25 20:49:53 +00002369 if (((SHELL_PARAM_PACKAGE*)Node)->Type == TypeStart) {
2370 if (StrnCmp(KeyString, ((SHELL_PARAM_PACKAGE*)Node)->Name, StrLen(KeyString)) == 0) {
2371 return (TRUE);
2372 }
2373 TempString = NULL;
2374 TempString = StrnCatGrow(&TempString, NULL, KeyString, StrLen(((SHELL_PARAM_PACKAGE*)Node)->Name));
2375 if (TempString != NULL) {
2376 if (StringNoCaseCompare(&KeyString, &((SHELL_PARAM_PACKAGE*)Node)->Name) == 0) {
2377 FreePool(TempString);
2378 return (TRUE);
2379 }
2380 FreePool(TempString);
2381 }
2382 } else if (StringNoCaseCompare(&KeyString, &((SHELL_PARAM_PACKAGE*)Node)->Name) == 0) {
jcarsey94b17fa2009-05-07 18:46:18 +00002383 return (TRUE);
2384 }
2385 }
2386 }
2387 return (FALSE);
2388}
2389/**
jcarseya405b862010-09-14 05:18:09 +00002390 Returns value from command line argument.
jcarsey94b17fa2009-05-07 18:46:18 +00002391
jcarseya405b862010-09-14 05:18:09 +00002392 Value parameters are in the form of "-<Key> value" or "/<Key> value".
jcarsey1e6e84c2010-01-25 20:05:08 +00002393
jcarseya405b862010-09-14 05:18:09 +00002394 If CheckPackage is NULL, then return NULL.
jcarsey94b17fa2009-05-07 18:46:18 +00002395
jcarseya405b862010-09-14 05:18:09 +00002396 @param[in] CheckPackage The package of parsed command line arguments.
2397 @param[in] KeyString The Key of the command line argument to check for.
jcarsey94b17fa2009-05-07 18:46:18 +00002398
jcarseya405b862010-09-14 05:18:09 +00002399 @retval NULL The flag is not on the command line.
2400 @retval !=NULL The pointer to unicode string of the value.
2401**/
jcarsey94b17fa2009-05-07 18:46:18 +00002402CONST CHAR16*
2403EFIAPI
2404ShellCommandLineGetValue (
2405 IN CONST LIST_ENTRY *CheckPackage,
2406 IN CHAR16 *KeyString
jcarseya405b862010-09-14 05:18:09 +00002407 )
2408{
jcarsey94b17fa2009-05-07 18:46:18 +00002409 LIST_ENTRY *Node;
jcarsey252d9452011-03-25 20:49:53 +00002410 CHAR16 *TempString;
jcarsey94b17fa2009-05-07 18:46:18 +00002411
2412 //
ydong100c1950b2011-10-13 02:37:35 +00002413 // return NULL for no package or KeyString is NULL
jcarsey94b17fa2009-05-07 18:46:18 +00002414 //
ydong100c1950b2011-10-13 02:37:35 +00002415 if (CheckPackage == NULL || KeyString == NULL) {
jcarsey94b17fa2009-05-07 18:46:18 +00002416 return (NULL);
2417 }
2418
2419 //
2420 // enumerate through the list of parametrs
2421 //
jcarsey1e6e84c2010-01-25 20:05:08 +00002422 for ( Node = GetFirstNode(CheckPackage)
2423 ; !IsNull (CheckPackage, Node)
2424 ; Node = GetNextNode(CheckPackage, Node)
jcarsey252d9452011-03-25 20:49:53 +00002425 ){
jcarsey94b17fa2009-05-07 18:46:18 +00002426 //
jcarsey252d9452011-03-25 20:49:53 +00002427 // If the Name matches, return TRUE (and there may be NULL name)
jcarsey94b17fa2009-05-07 18:46:18 +00002428 //
2429 if (((SHELL_PARAM_PACKAGE*)Node)->Name != NULL) {
jcarsey9eb53ac2009-07-08 17:26:58 +00002430 //
2431 // If Type is TypeStart then only compare the begining of the strings
2432 //
jcarsey252d9452011-03-25 20:49:53 +00002433 if (((SHELL_PARAM_PACKAGE*)Node)->Type == TypeStart) {
2434 if (StrnCmp(KeyString, ((SHELL_PARAM_PACKAGE*)Node)->Name, StrLen(KeyString)) == 0) {
2435 return (((SHELL_PARAM_PACKAGE*)Node)->Name + StrLen(KeyString));
2436 }
2437 TempString = NULL;
2438 TempString = StrnCatGrow(&TempString, NULL, KeyString, StrLen(((SHELL_PARAM_PACKAGE*)Node)->Name));
2439 if (TempString != NULL) {
2440 if (StringNoCaseCompare(&KeyString, &((SHELL_PARAM_PACKAGE*)Node)->Name) == 0) {
2441 FreePool(TempString);
2442 return (((SHELL_PARAM_PACKAGE*)Node)->Name + StrLen(KeyString));
2443 }
2444 FreePool(TempString);
2445 }
2446 } else if (StringNoCaseCompare(&KeyString, &((SHELL_PARAM_PACKAGE*)Node)->Name) == 0) {
jcarsey94b17fa2009-05-07 18:46:18 +00002447 return (((SHELL_PARAM_PACKAGE*)Node)->Value);
2448 }
2449 }
2450 }
2451 return (NULL);
2452}
jcarseya405b862010-09-14 05:18:09 +00002453
jcarsey94b17fa2009-05-07 18:46:18 +00002454/**
jcarseya405b862010-09-14 05:18:09 +00002455 Returns raw value from command line argument.
jcarsey94b17fa2009-05-07 18:46:18 +00002456
jcarseya405b862010-09-14 05:18:09 +00002457 Raw value parameters are in the form of "value" in a specific position in the list.
jcarsey1e6e84c2010-01-25 20:05:08 +00002458
jcarseya405b862010-09-14 05:18:09 +00002459 If CheckPackage is NULL, then return NULL.
jcarsey94b17fa2009-05-07 18:46:18 +00002460
jcarseya405b862010-09-14 05:18:09 +00002461 @param[in] CheckPackage The package of parsed command line arguments.
2462 @param[in] Position The position of the value.
jcarsey94b17fa2009-05-07 18:46:18 +00002463
jcarseya405b862010-09-14 05:18:09 +00002464 @retval NULL The flag is not on the command line.
2465 @retval !=NULL The pointer to unicode string of the value.
jcarsey94b17fa2009-05-07 18:46:18 +00002466 **/
2467CONST CHAR16*
2468EFIAPI
2469ShellCommandLineGetRawValue (
jcarseya405b862010-09-14 05:18:09 +00002470 IN CONST LIST_ENTRY * CONST CheckPackage,
2471 IN UINTN Position
2472 )
2473{
jcarsey94b17fa2009-05-07 18:46:18 +00002474 LIST_ENTRY *Node;
2475
2476 //
2477 // check for CheckPackage == NULL
2478 //
2479 if (CheckPackage == NULL) {
2480 return (NULL);
2481 }
2482
2483 //
2484 // enumerate through the list of parametrs
2485 //
jcarsey1e6e84c2010-01-25 20:05:08 +00002486 for ( Node = GetFirstNode(CheckPackage)
2487 ; !IsNull (CheckPackage, Node)
2488 ; Node = GetNextNode(CheckPackage, Node)
jcarseya405b862010-09-14 05:18:09 +00002489 ){
jcarsey94b17fa2009-05-07 18:46:18 +00002490 //
2491 // If the position matches, return the value
2492 //
2493 if (((SHELL_PARAM_PACKAGE*)Node)->OriginalPosition == Position) {
2494 return (((SHELL_PARAM_PACKAGE*)Node)->Value);
2495 }
2496 }
2497 return (NULL);
jcarseyb1f95a02009-06-16 00:23:19 +00002498}
jcarsey2247dde2009-11-09 18:08:58 +00002499
2500/**
jcarsey1e6e84c2010-01-25 20:05:08 +00002501 returns the number of command line value parameters that were parsed.
2502
jcarsey2247dde2009-11-09 18:08:58 +00002503 this will not include flags.
2504
jcarseya405b862010-09-14 05:18:09 +00002505 @param[in] CheckPackage The package of parsed command line arguments.
2506
jcarsey2247dde2009-11-09 18:08:58 +00002507 @retval (UINTN)-1 No parsing has ocurred
2508 @return other The number of value parameters found
2509**/
2510UINTN
2511EFIAPI
2512ShellCommandLineGetCount(
jcarseya405b862010-09-14 05:18:09 +00002513 IN CONST LIST_ENTRY *CheckPackage
jcarsey125c2cf2009-11-18 21:36:50 +00002514 )
2515{
jcarseya405b862010-09-14 05:18:09 +00002516 LIST_ENTRY *Node1;
2517 UINTN Count;
2518
2519 if (CheckPackage == NULL) {
2520 return (0);
2521 }
2522 for ( Node1 = GetFirstNode(CheckPackage), Count = 0
2523 ; !IsNull (CheckPackage, Node1)
2524 ; Node1 = GetNextNode(CheckPackage, Node1)
2525 ){
2526 if (((SHELL_PARAM_PACKAGE*)Node1)->Name == NULL) {
2527 Count++;
2528 }
2529 }
2530 return (Count);
jcarsey2247dde2009-11-09 18:08:58 +00002531}
2532
jcarsey975136a2009-06-16 19:03:54 +00002533/**
Bruce Crancceb4eb2015-07-08 01:54:46 +00002534 Determines if a parameter is duplicated.
jcarsey36a9d672009-11-20 21:13:41 +00002535
jcarsey1e6e84c2010-01-25 20:05:08 +00002536 If Param is not NULL then it will point to a callee allocated string buffer
jcarsey36a9d672009-11-20 21:13:41 +00002537 with the parameter value if a duplicate is found.
2538
2539 If CheckPackage is NULL, then ASSERT.
2540
2541 @param[in] CheckPackage The package of parsed command line arguments.
2542 @param[out] Param Upon finding one, a pointer to the duplicated parameter.
2543
2544 @retval EFI_SUCCESS No parameters were duplicated.
2545 @retval EFI_DEVICE_ERROR A duplicate was found.
2546 **/
2547EFI_STATUS
2548EFIAPI
2549ShellCommandLineCheckDuplicate (
2550 IN CONST LIST_ENTRY *CheckPackage,
2551 OUT CHAR16 **Param
2552 )
2553{
2554 LIST_ENTRY *Node1;
2555 LIST_ENTRY *Node2;
jcarsey1e6e84c2010-01-25 20:05:08 +00002556
jcarsey36a9d672009-11-20 21:13:41 +00002557 ASSERT(CheckPackage != NULL);
2558
jcarsey1e6e84c2010-01-25 20:05:08 +00002559 for ( Node1 = GetFirstNode(CheckPackage)
2560 ; !IsNull (CheckPackage, Node1)
2561 ; Node1 = GetNextNode(CheckPackage, Node1)
jcarseya405b862010-09-14 05:18:09 +00002562 ){
jcarsey1e6e84c2010-01-25 20:05:08 +00002563 for ( Node2 = GetNextNode(CheckPackage, Node1)
2564 ; !IsNull (CheckPackage, Node2)
2565 ; Node2 = GetNextNode(CheckPackage, Node2)
jcarseya405b862010-09-14 05:18:09 +00002566 ){
2567 if ((((SHELL_PARAM_PACKAGE*)Node1)->Name != NULL) && (((SHELL_PARAM_PACKAGE*)Node2)->Name != NULL) && StrCmp(((SHELL_PARAM_PACKAGE*)Node1)->Name, ((SHELL_PARAM_PACKAGE*)Node2)->Name) == 0) {
jcarsey36a9d672009-11-20 21:13:41 +00002568 if (Param != NULL) {
2569 *Param = NULL;
2570 *Param = StrnCatGrow(Param, NULL, ((SHELL_PARAM_PACKAGE*)Node1)->Name, 0);
2571 }
2572 return (EFI_DEVICE_ERROR);
2573 }
2574 }
2575 }
2576 return (EFI_SUCCESS);
2577}
2578
2579/**
jcarsey1e6e84c2010-01-25 20:05:08 +00002580 This is a find and replace function. Upon successful return the NewString is a copy of
jcarsey975136a2009-06-16 19:03:54 +00002581 SourceString with each instance of FindTarget replaced with ReplaceWith.
2582
jcarseyb3011f42010-01-11 21:49:04 +00002583 If SourceString and NewString overlap the behavior is undefined.
2584
jcarsey975136a2009-06-16 19:03:54 +00002585 If the string would grow bigger than NewSize it will halt and return error.
2586
ydong104ff7e372011-09-02 08:05:34 +00002587 @param[in] SourceString The string with source buffer.
2588 @param[in, out] NewString The string with resultant buffer.
2589 @param[in] NewSize The size in bytes of NewString.
2590 @param[in] FindTarget The string to look for.
2591 @param[in] ReplaceWith The string to replace FindTarget with.
2592 @param[in] SkipPreCarrot If TRUE will skip a FindTarget that has a '^'
2593 immediately before it.
2594 @param[in] ParameterReplacing If TRUE will add "" around items with spaces.
jcarsey975136a2009-06-16 19:03:54 +00002595
jcarsey969c7832010-01-13 16:46:33 +00002596 @retval EFI_INVALID_PARAMETER SourceString was NULL.
2597 @retval EFI_INVALID_PARAMETER NewString was NULL.
2598 @retval EFI_INVALID_PARAMETER FindTarget was NULL.
2599 @retval EFI_INVALID_PARAMETER ReplaceWith was NULL.
2600 @retval EFI_INVALID_PARAMETER FindTarget had length < 1.
2601 @retval EFI_INVALID_PARAMETER SourceString had length < 1.
jcarsey1e6e84c2010-01-25 20:05:08 +00002602 @retval EFI_BUFFER_TOO_SMALL NewSize was less than the minimum size to hold
jcarsey969c7832010-01-13 16:46:33 +00002603 the new string (truncation occurred).
jcarseya405b862010-09-14 05:18:09 +00002604 @retval EFI_SUCCESS The string was successfully copied with replacement.
jcarsey975136a2009-06-16 19:03:54 +00002605**/
jcarsey975136a2009-06-16 19:03:54 +00002606EFI_STATUS
2607EFIAPI
jcarseya405b862010-09-14 05:18:09 +00002608ShellCopySearchAndReplace(
jcarsey975136a2009-06-16 19:03:54 +00002609 IN CHAR16 CONST *SourceString,
jcarseya405b862010-09-14 05:18:09 +00002610 IN OUT CHAR16 *NewString,
jcarsey975136a2009-06-16 19:03:54 +00002611 IN UINTN NewSize,
2612 IN CONST CHAR16 *FindTarget,
jcarsey969c7832010-01-13 16:46:33 +00002613 IN CONST CHAR16 *ReplaceWith,
jcarseya405b862010-09-14 05:18:09 +00002614 IN CONST BOOLEAN SkipPreCarrot,
2615 IN CONST BOOLEAN ParameterReplacing
jcarsey1e6e84c2010-01-25 20:05:08 +00002616 )
jcarsey2247dde2009-11-09 18:08:58 +00002617{
jcarsey01582942009-07-10 19:46:17 +00002618 UINTN Size;
jcarseya405b862010-09-14 05:18:09 +00002619 CHAR16 *Replace;
2620
jcarsey975136a2009-06-16 19:03:54 +00002621 if ( (SourceString == NULL)
2622 || (NewString == NULL)
2623 || (FindTarget == NULL)
2624 || (ReplaceWith == NULL)
2625 || (StrLen(FindTarget) < 1)
2626 || (StrLen(SourceString) < 1)
jcarseya405b862010-09-14 05:18:09 +00002627 ){
jcarsey975136a2009-06-16 19:03:54 +00002628 return (EFI_INVALID_PARAMETER);
2629 }
jcarseya405b862010-09-14 05:18:09 +00002630 Replace = NULL;
2631 if (StrStr(ReplaceWith, L" ") == NULL || !ParameterReplacing) {
2632 Replace = StrnCatGrow(&Replace, NULL, ReplaceWith, 0);
2633 } else {
2634 Replace = AllocateZeroPool(StrSize(ReplaceWith) + 2*sizeof(CHAR16));
jcarseybeab0fc2011-10-10 17:26:25 +00002635 if (Replace != NULL) {
2636 UnicodeSPrint(Replace, StrSize(ReplaceWith) + 2*sizeof(CHAR16), L"\"%s\"", ReplaceWith);
2637 }
jcarseya405b862010-09-14 05:18:09 +00002638 }
jcarsey3e082d52010-10-04 16:44:57 +00002639 if (Replace == NULL) {
2640 return (EFI_OUT_OF_RESOURCES);
2641 }
Jaben Carsey98c16be2014-08-19 21:00:34 +00002642 NewString = ZeroMem(NewString, NewSize);
jcarsey2247dde2009-11-09 18:08:58 +00002643 while (*SourceString != CHAR_NULL) {
jcarsey969c7832010-01-13 16:46:33 +00002644 //
jcarseya405b862010-09-14 05:18:09 +00002645 // if we find the FindTarget and either Skip == FALSE or Skip and we
jcarsey969c7832010-01-13 16:46:33 +00002646 // dont have a carrot do a replace...
2647 //
jcarsey1e6e84c2010-01-25 20:05:08 +00002648 if (StrnCmp(SourceString, FindTarget, StrLen(FindTarget)) == 0
jcarseya405b862010-09-14 05:18:09 +00002649 && ((SkipPreCarrot && *(SourceString-1) != L'^') || !SkipPreCarrot)
2650 ){
jcarsey975136a2009-06-16 19:03:54 +00002651 SourceString += StrLen(FindTarget);
jcarsey01582942009-07-10 19:46:17 +00002652 Size = StrSize(NewString);
jcarseya405b862010-09-14 05:18:09 +00002653 if ((Size + (StrLen(Replace)*sizeof(CHAR16))) > NewSize) {
2654 FreePool(Replace);
jcarsey975136a2009-06-16 19:03:54 +00002655 return (EFI_BUFFER_TOO_SMALL);
2656 }
Qiu Shumine75390f2015-06-30 03:18:31 +00002657 StrCatS(NewString, NewSize/sizeof(CHAR16), Replace);
jcarsey975136a2009-06-16 19:03:54 +00002658 } else {
jcarsey01582942009-07-10 19:46:17 +00002659 Size = StrSize(NewString);
2660 if (Size + sizeof(CHAR16) > NewSize) {
jcarseya405b862010-09-14 05:18:09 +00002661 FreePool(Replace);
jcarsey975136a2009-06-16 19:03:54 +00002662 return (EFI_BUFFER_TOO_SMALL);
2663 }
Qiu Shumine75390f2015-06-30 03:18:31 +00002664 StrnCatS(NewString, NewSize/sizeof(CHAR16), SourceString, 1);
jcarsey975136a2009-06-16 19:03:54 +00002665 SourceString++;
2666 }
2667 }
jcarseya405b862010-09-14 05:18:09 +00002668 FreePool(Replace);
jcarsey975136a2009-06-16 19:03:54 +00002669 return (EFI_SUCCESS);
2670}
jcarseyb1f95a02009-06-16 00:23:19 +00002671
2672/**
jcarseye2f82972009-12-01 05:40:24 +00002673 Internal worker function to output a string.
2674
2675 This function will output a string to the correct StdOut.
2676
2677 @param[in] String The string to print out.
2678
2679 @retval EFI_SUCCESS The operation was sucessful.
2680 @retval !EFI_SUCCESS The operation failed.
2681**/
2682EFI_STATUS
2683EFIAPI
2684InternalPrintTo (
2685 IN CONST CHAR16 *String
2686 )
2687{
2688 UINTN Size;
2689 Size = StrSize(String) - sizeof(CHAR16);
jcarseya405b862010-09-14 05:18:09 +00002690 if (Size == 0) {
2691 return (EFI_SUCCESS);
2692 }
jcarsey366f81a2011-06-27 21:04:22 +00002693 if (gEfiShellParametersProtocol != NULL) {
2694 return (gEfiShellProtocol->WriteFile(gEfiShellParametersProtocol->StdOut, &Size, (VOID*)String));
jcarseye2f82972009-12-01 05:40:24 +00002695 }
2696 if (mEfiShellInterface != NULL) {
jcarsey06c355b2012-03-26 21:00:39 +00002697 if (mEfiShellInterface->RedirArgc == 0) {
jcarsey49bd4982012-01-27 18:42:43 +00002698 //
2699 // Divide in half for old shell. Must be string length not size.
jcarsey06c355b2012-03-26 21:00:39 +00002700 //
2701 Size /=2; // Divide in half only when no redirection.
2702 }
jcarseya405b862010-09-14 05:18:09 +00002703 return (mEfiShellInterface->StdOut->Write(mEfiShellInterface->StdOut, &Size, (VOID*)String));
jcarseye2f82972009-12-01 05:40:24 +00002704 }
2705 ASSERT(FALSE);
2706 return (EFI_UNSUPPORTED);
2707}
2708
2709/**
jcarseyb1f95a02009-06-16 00:23:19 +00002710 Print at a specific location on the screen.
2711
jcarseyf1b87e72009-06-17 00:52:11 +00002712 This function will move the cursor to a given screen location and print the specified string
jcarsey1e6e84c2010-01-25 20:05:08 +00002713
2714 If -1 is specified for either the Row or Col the current screen location for BOTH
jcarseyf1b87e72009-06-17 00:52:11 +00002715 will be used.
jcarseyb1f95a02009-06-16 00:23:19 +00002716
2717 if either Row or Col is out of range for the current console, then ASSERT
2718 if Format is NULL, then ASSERT
2719
jcarsey1e6e84c2010-01-25 20:05:08 +00002720 In addition to the standard %-based flags as supported by UefiLib Print() this supports
jcarseyb1f95a02009-06-16 00:23:19 +00002721 the following additional flags:
2722 %N - Set output attribute to normal
2723 %H - Set output attribute to highlight
2724 %E - Set output attribute to error
2725 %B - Set output attribute to blue color
2726 %V - Set output attribute to green color
2727
2728 Note: The background color is controlled by the shell command cls.
2729
jcarseyb1f95a02009-06-16 00:23:19 +00002730 @param[in] Col the column to print at
jcarsey252d9452011-03-25 20:49:53 +00002731 @param[in] Row the row to print at
jcarseyb1f95a02009-06-16 00:23:19 +00002732 @param[in] Format the format string
jcarsey2247dde2009-11-09 18:08:58 +00002733 @param[in] Marker the marker for the variable argument list
jcarseyb1f95a02009-06-16 00:23:19 +00002734
jcarseya405b862010-09-14 05:18:09 +00002735 @return EFI_SUCCESS The operation was successful.
2736 @return EFI_DEVICE_ERROR The console device reported an error.
jcarseyb1f95a02009-06-16 00:23:19 +00002737**/
jcarseya405b862010-09-14 05:18:09 +00002738EFI_STATUS
jcarseyb1f95a02009-06-16 00:23:19 +00002739EFIAPI
jcarsey2247dde2009-11-09 18:08:58 +00002740InternalShellPrintWorker(
jcarseyb1f95a02009-06-16 00:23:19 +00002741 IN INT32 Col OPTIONAL,
2742 IN INT32 Row OPTIONAL,
2743 IN CONST CHAR16 *Format,
jcarsey252d9452011-03-25 20:49:53 +00002744 IN VA_LIST Marker
jcarsey1e6e84c2010-01-25 20:05:08 +00002745 )
jcarsey2247dde2009-11-09 18:08:58 +00002746{
jcarseyb1f95a02009-06-16 00:23:19 +00002747 EFI_STATUS Status;
jcarsey975136a2009-06-16 19:03:54 +00002748 CHAR16 *ResumeLocation;
2749 CHAR16 *FormatWalker;
jcarseya405b862010-09-14 05:18:09 +00002750 UINTN OriginalAttribute;
jcarsey89e85372011-04-13 23:37:50 +00002751 CHAR16 *mPostReplaceFormat;
2752 CHAR16 *mPostReplaceFormat2;
2753
2754 mPostReplaceFormat = AllocateZeroPool (PcdGet16 (PcdShellPrintBufferSize));
2755 mPostReplaceFormat2 = AllocateZeroPool (PcdGet16 (PcdShellPrintBufferSize));
jcarseya405b862010-09-14 05:18:09 +00002756
jcarseyf8d3e682011-04-19 17:54:42 +00002757 if (mPostReplaceFormat == NULL || mPostReplaceFormat2 == NULL) {
2758 SHELL_FREE_NON_NULL(mPostReplaceFormat);
2759 SHELL_FREE_NON_NULL(mPostReplaceFormat2);
2760 return (EFI_OUT_OF_RESOURCES);
2761 }
2762
jcarseya405b862010-09-14 05:18:09 +00002763 Status = EFI_SUCCESS;
2764 OriginalAttribute = gST->ConOut->Mode->Attribute;
jcarsey1e6e84c2010-01-25 20:05:08 +00002765
jcarsey975136a2009-06-16 19:03:54 +00002766 //
2767 // Back and forth each time fixing up 1 of our flags...
2768 //
jcarseya405b862010-09-14 05:18:09 +00002769 Status = ShellCopySearchAndReplace(Format, mPostReplaceFormat, PcdGet16 (PcdShellPrintBufferSize), L"%N", L"%%N", FALSE, FALSE);
jcarsey975136a2009-06-16 19:03:54 +00002770 ASSERT_EFI_ERROR(Status);
jcarseya405b862010-09-14 05:18:09 +00002771 Status = ShellCopySearchAndReplace(mPostReplaceFormat, mPostReplaceFormat2, PcdGet16 (PcdShellPrintBufferSize), L"%E", L"%%E", FALSE, FALSE);
jcarsey975136a2009-06-16 19:03:54 +00002772 ASSERT_EFI_ERROR(Status);
jcarseya405b862010-09-14 05:18:09 +00002773 Status = ShellCopySearchAndReplace(mPostReplaceFormat2, mPostReplaceFormat, PcdGet16 (PcdShellPrintBufferSize), L"%H", L"%%H", FALSE, FALSE);
jcarsey975136a2009-06-16 19:03:54 +00002774 ASSERT_EFI_ERROR(Status);
jcarseya405b862010-09-14 05:18:09 +00002775 Status = ShellCopySearchAndReplace(mPostReplaceFormat, mPostReplaceFormat2, PcdGet16 (PcdShellPrintBufferSize), L"%B", L"%%B", FALSE, FALSE);
jcarsey975136a2009-06-16 19:03:54 +00002776 ASSERT_EFI_ERROR(Status);
jcarseya405b862010-09-14 05:18:09 +00002777 Status = ShellCopySearchAndReplace(mPostReplaceFormat2, mPostReplaceFormat, PcdGet16 (PcdShellPrintBufferSize), L"%V", L"%%V", FALSE, FALSE);
jcarsey975136a2009-06-16 19:03:54 +00002778 ASSERT_EFI_ERROR(Status);
2779
2780 //
2781 // Use the last buffer from replacing to print from...
2782 //
jcarseya405b862010-09-14 05:18:09 +00002783 UnicodeVSPrint (mPostReplaceFormat2, PcdGet16 (PcdShellPrintBufferSize), mPostReplaceFormat, Marker);
jcarseyb1f95a02009-06-16 00:23:19 +00002784
2785 if (Col != -1 && Row != -1) {
jcarseyb1f95a02009-06-16 00:23:19 +00002786 Status = gST->ConOut->SetCursorPosition(gST->ConOut, Col, Row);
jcarsey975136a2009-06-16 19:03:54 +00002787 }
2788
jcarseyecd3d592009-12-07 18:05:00 +00002789 FormatWalker = mPostReplaceFormat2;
jcarsey2247dde2009-11-09 18:08:58 +00002790 while (*FormatWalker != CHAR_NULL) {
jcarsey975136a2009-06-16 19:03:54 +00002791 //
2792 // Find the next attribute change request
2793 //
2794 ResumeLocation = StrStr(FormatWalker, L"%");
2795 if (ResumeLocation != NULL) {
jcarsey2247dde2009-11-09 18:08:58 +00002796 *ResumeLocation = CHAR_NULL;
jcarsey975136a2009-06-16 19:03:54 +00002797 }
2798 //
2799 // print the current FormatWalker string
2800 //
jcarseya405b862010-09-14 05:18:09 +00002801 if (StrLen(FormatWalker)>0) {
2802 Status = InternalPrintTo(FormatWalker);
2803 if (EFI_ERROR(Status)) {
2804 break;
2805 }
2806 }
2807
jcarsey975136a2009-06-16 19:03:54 +00002808 //
2809 // update the attribute
2810 //
2811 if (ResumeLocation != NULL) {
jcarsey5d46f172011-08-23 15:34:23 +00002812 if (*(ResumeLocation-1) == L'^') {
2813 //
jcarsey8bb74412012-01-30 18:44:41 +00002814 // Move cursor back 1 position to overwrite the ^
2815 //
2816 gST->ConOut->SetCursorPosition(gST->ConOut, gST->ConOut->Mode->CursorColumn - 1, gST->ConOut->Mode->CursorRow);
2817
2818 //
jcarsey5d46f172011-08-23 15:34:23 +00002819 // Print a simple '%' symbol
2820 //
2821 Status = InternalPrintTo(L"%");
2822 ResumeLocation = ResumeLocation - 1;
2823 } else {
2824 switch (*(ResumeLocation+1)) {
2825 case (L'N'):
2826 gST->ConOut->SetAttribute(gST->ConOut, OriginalAttribute);
jcarseya405b862010-09-14 05:18:09 +00002827 break;
jcarsey5d46f172011-08-23 15:34:23 +00002828 case (L'E'):
2829 gST->ConOut->SetAttribute(gST->ConOut, EFI_TEXT_ATTR(EFI_YELLOW, ((OriginalAttribute&(BIT4|BIT5|BIT6))>>4)));
2830 break;
2831 case (L'H'):
2832 gST->ConOut->SetAttribute(gST->ConOut, EFI_TEXT_ATTR(EFI_WHITE, ((OriginalAttribute&(BIT4|BIT5|BIT6))>>4)));
2833 break;
2834 case (L'B'):
2835 gST->ConOut->SetAttribute(gST->ConOut, EFI_TEXT_ATTR(EFI_BLUE, ((OriginalAttribute&(BIT4|BIT5|BIT6))>>4)));
2836 break;
2837 case (L'V'):
2838 gST->ConOut->SetAttribute(gST->ConOut, EFI_TEXT_ATTR(EFI_GREEN, ((OriginalAttribute&(BIT4|BIT5|BIT6))>>4)));
2839 break;
2840 default:
2841 //
2842 // Print a simple '%' symbol
2843 //
2844 Status = InternalPrintTo(L"%");
2845 if (EFI_ERROR(Status)) {
2846 break;
2847 }
2848 ResumeLocation = ResumeLocation - 1;
2849 break;
2850 }
jcarsey975136a2009-06-16 19:03:54 +00002851 }
2852 } else {
2853 //
2854 // reset to normal now...
2855 //
jcarsey975136a2009-06-16 19:03:54 +00002856 break;
2857 }
2858
2859 //
2860 // update FormatWalker to Resume + 2 (skip the % and the indicator)
2861 //
2862 FormatWalker = ResumeLocation + 2;
2863 }
jcarseyb1f95a02009-06-16 00:23:19 +00002864
jcarseya405b862010-09-14 05:18:09 +00002865 gST->ConOut->SetAttribute(gST->ConOut, OriginalAttribute);
jcarsey89e85372011-04-13 23:37:50 +00002866
2867 SHELL_FREE_NON_NULL(mPostReplaceFormat);
2868 SHELL_FREE_NON_NULL(mPostReplaceFormat2);
jcarseya405b862010-09-14 05:18:09 +00002869 return (Status);
jcarsey5f7431d2009-07-10 18:06:01 +00002870}
jcarsey2247dde2009-11-09 18:08:58 +00002871
2872/**
2873 Print at a specific location on the screen.
2874
jcarseye2f82972009-12-01 05:40:24 +00002875 This function will move the cursor to a given screen location and print the specified string.
jcarsey1e6e84c2010-01-25 20:05:08 +00002876
2877 If -1 is specified for either the Row or Col the current screen location for BOTH
jcarsey2247dde2009-11-09 18:08:58 +00002878 will be used.
2879
jcarseye2f82972009-12-01 05:40:24 +00002880 If either Row or Col is out of range for the current console, then ASSERT.
2881 If Format is NULL, then ASSERT.
jcarsey2247dde2009-11-09 18:08:58 +00002882
jcarsey1e6e84c2010-01-25 20:05:08 +00002883 In addition to the standard %-based flags as supported by UefiLib Print() this supports
jcarsey2247dde2009-11-09 18:08:58 +00002884 the following additional flags:
2885 %N - Set output attribute to normal
2886 %H - Set output attribute to highlight
2887 %E - Set output attribute to error
2888 %B - Set output attribute to blue color
2889 %V - Set output attribute to green color
2890
2891 Note: The background color is controlled by the shell command cls.
2892
jcarsey2247dde2009-11-09 18:08:58 +00002893 @param[in] Col the column to print at
jcarseya405b862010-09-14 05:18:09 +00002894 @param[in] Row the row to print at
jcarsey2247dde2009-11-09 18:08:58 +00002895 @param[in] Format the format string
jcarseya405b862010-09-14 05:18:09 +00002896 @param[in] ... The variable argument list.
jcarsey2247dde2009-11-09 18:08:58 +00002897
jcarseya405b862010-09-14 05:18:09 +00002898 @return EFI_SUCCESS The printing was successful.
2899 @return EFI_DEVICE_ERROR The console device reported an error.
jcarsey2247dde2009-11-09 18:08:58 +00002900**/
jcarseya405b862010-09-14 05:18:09 +00002901EFI_STATUS
jcarsey2247dde2009-11-09 18:08:58 +00002902EFIAPI
2903ShellPrintEx(
2904 IN INT32 Col OPTIONAL,
2905 IN INT32 Row OPTIONAL,
2906 IN CONST CHAR16 *Format,
2907 ...
jcarsey1e6e84c2010-01-25 20:05:08 +00002908 )
jcarsey2247dde2009-11-09 18:08:58 +00002909{
2910 VA_LIST Marker;
jcarseya405b862010-09-14 05:18:09 +00002911 EFI_STATUS RetVal;
jcarsey3e082d52010-10-04 16:44:57 +00002912 if (Format == NULL) {
2913 return (EFI_INVALID_PARAMETER);
2914 }
jcarsey2247dde2009-11-09 18:08:58 +00002915 VA_START (Marker, Format);
jcarseya405b862010-09-14 05:18:09 +00002916 RetVal = InternalShellPrintWorker(Col, Row, Format, Marker);
jcarseye2f82972009-12-01 05:40:24 +00002917 VA_END(Marker);
jcarseya405b862010-09-14 05:18:09 +00002918 return(RetVal);
jcarsey2247dde2009-11-09 18:08:58 +00002919}
2920
2921/**
2922 Print at a specific location on the screen.
2923
jcarseye2f82972009-12-01 05:40:24 +00002924 This function will move the cursor to a given screen location and print the specified string.
jcarsey1e6e84c2010-01-25 20:05:08 +00002925
2926 If -1 is specified for either the Row or Col the current screen location for BOTH
jcarseye2f82972009-12-01 05:40:24 +00002927 will be used.
jcarsey2247dde2009-11-09 18:08:58 +00002928
jcarseye2f82972009-12-01 05:40:24 +00002929 If either Row or Col is out of range for the current console, then ASSERT.
2930 If Format is NULL, then ASSERT.
jcarsey2247dde2009-11-09 18:08:58 +00002931
jcarsey1e6e84c2010-01-25 20:05:08 +00002932 In addition to the standard %-based flags as supported by UefiLib Print() this supports
jcarsey2247dde2009-11-09 18:08:58 +00002933 the following additional flags:
jcarsey1e6e84c2010-01-25 20:05:08 +00002934 %N - Set output attribute to normal.
2935 %H - Set output attribute to highlight.
2936 %E - Set output attribute to error.
2937 %B - Set output attribute to blue color.
2938 %V - Set output attribute to green color.
jcarsey2247dde2009-11-09 18:08:58 +00002939
2940 Note: The background color is controlled by the shell command cls.
2941
jcarsey1e6e84c2010-01-25 20:05:08 +00002942 @param[in] Col The column to print at.
jcarseya405b862010-09-14 05:18:09 +00002943 @param[in] Row The row to print at.
jcarsey1e6e84c2010-01-25 20:05:08 +00002944 @param[in] Language The language of the string to retrieve. If this parameter
2945 is NULL, then the current platform language is used.
2946 @param[in] HiiFormatStringId The format string Id for getting from Hii.
2947 @param[in] HiiFormatHandle The format string Handle for getting from Hii.
jcarseya405b862010-09-14 05:18:09 +00002948 @param[in] ... The variable argument list.
jcarsey2247dde2009-11-09 18:08:58 +00002949
jcarseya405b862010-09-14 05:18:09 +00002950 @return EFI_SUCCESS The printing was successful.
2951 @return EFI_DEVICE_ERROR The console device reported an error.
jcarsey2247dde2009-11-09 18:08:58 +00002952**/
jcarseya405b862010-09-14 05:18:09 +00002953EFI_STATUS
jcarsey2247dde2009-11-09 18:08:58 +00002954EFIAPI
2955ShellPrintHiiEx(
2956 IN INT32 Col OPTIONAL,
2957 IN INT32 Row OPTIONAL,
jcarsey1e6e84c2010-01-25 20:05:08 +00002958 IN CONST CHAR8 *Language OPTIONAL,
jcarsey2247dde2009-11-09 18:08:58 +00002959 IN CONST EFI_STRING_ID HiiFormatStringId,
2960 IN CONST EFI_HANDLE HiiFormatHandle,
2961 ...
2962 )
2963{
2964 VA_LIST Marker;
2965 CHAR16 *HiiFormatString;
jcarseya405b862010-09-14 05:18:09 +00002966 EFI_STATUS RetVal;
jcarsey2247dde2009-11-09 18:08:58 +00002967
2968 VA_START (Marker, HiiFormatHandle);
jcarsey1e6e84c2010-01-25 20:05:08 +00002969 HiiFormatString = HiiGetString(HiiFormatHandle, HiiFormatStringId, Language);
jcarsey2247dde2009-11-09 18:08:58 +00002970 ASSERT(HiiFormatString != NULL);
2971
2972 RetVal = InternalShellPrintWorker(Col, Row, HiiFormatString, Marker);
2973
jcarseya405b862010-09-14 05:18:09 +00002974 SHELL_FREE_NON_NULL(HiiFormatString);
jcarseye2f82972009-12-01 05:40:24 +00002975 VA_END(Marker);
jcarsey2247dde2009-11-09 18:08:58 +00002976
2977 return (RetVal);
2978}
2979
2980/**
2981 Function to determine if a given filename represents a file or a directory.
2982
2983 @param[in] DirName Path to directory to test.
2984
jcarseyc8c22592011-10-17 17:49:21 +00002985 @retval EFI_SUCCESS The Path represents a directory
2986 @retval EFI_NOT_FOUND The Path does not represent a directory
2987 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
2988 @return The path failed to open
jcarsey2247dde2009-11-09 18:08:58 +00002989**/
2990EFI_STATUS
2991EFIAPI
2992ShellIsDirectory(
2993 IN CONST CHAR16 *DirName
2994 )
2995{
2996 EFI_STATUS Status;
jcarseya405b862010-09-14 05:18:09 +00002997 SHELL_FILE_HANDLE Handle;
jcarsey3e082d52010-10-04 16:44:57 +00002998 CHAR16 *TempLocation;
2999 CHAR16 *TempLocation2;
jcarsey2247dde2009-11-09 18:08:58 +00003000
jcarseyecd3d592009-12-07 18:05:00 +00003001 ASSERT(DirName != NULL);
3002
jcarseya405b862010-09-14 05:18:09 +00003003 Handle = NULL;
3004 TempLocation = NULL;
jcarsey2247dde2009-11-09 18:08:58 +00003005
3006 Status = ShellOpenFileByName(DirName, &Handle, EFI_FILE_MODE_READ, 0);
3007 if (EFI_ERROR(Status)) {
jcarseya405b862010-09-14 05:18:09 +00003008 //
3009 // try good logic first.
3010 //
jcarsey366f81a2011-06-27 21:04:22 +00003011 if (gEfiShellProtocol != NULL) {
jcarsey3e082d52010-10-04 16:44:57 +00003012 TempLocation = StrnCatGrow(&TempLocation, NULL, DirName, 0);
jcarseyc8c22592011-10-17 17:49:21 +00003013 if (TempLocation == NULL) {
3014 ShellCloseFile(&Handle);
3015 return (EFI_OUT_OF_RESOURCES);
3016 }
jcarsey3e082d52010-10-04 16:44:57 +00003017 TempLocation2 = StrStr(TempLocation, L":");
3018 if (TempLocation2 != NULL && StrLen(StrStr(TempLocation, L":")) == 2) {
3019 *(TempLocation2+1) = CHAR_NULL;
jcarseya405b862010-09-14 05:18:09 +00003020 }
jcarsey366f81a2011-06-27 21:04:22 +00003021 if (gEfiShellProtocol->GetDevicePathFromMap(TempLocation) != NULL) {
jcarseya405b862010-09-14 05:18:09 +00003022 FreePool(TempLocation);
3023 return (EFI_SUCCESS);
3024 }
3025 FreePool(TempLocation);
3026 } else {
3027 //
3028 // probably a map name?!?!!?
3029 //
3030 TempLocation = StrStr(DirName, L"\\");
3031 if (TempLocation != NULL && *(TempLocation+1) == CHAR_NULL) {
3032 return (EFI_SUCCESS);
3033 }
3034 }
jcarsey2247dde2009-11-09 18:08:58 +00003035 return (Status);
3036 }
3037
3038 if (FileHandleIsDirectory(Handle) == EFI_SUCCESS) {
3039 ShellCloseFile(&Handle);
3040 return (EFI_SUCCESS);
3041 }
3042 ShellCloseFile(&Handle);
3043 return (EFI_NOT_FOUND);
3044}
3045
jcarsey125c2cf2009-11-18 21:36:50 +00003046/**
jcarsey36a9d672009-11-20 21:13:41 +00003047 Function to determine if a given filename represents a file.
3048
3049 @param[in] Name Path to file to test.
3050
3051 @retval EFI_SUCCESS The Path represents a file.
3052 @retval EFI_NOT_FOUND The Path does not represent a file.
3053 @retval other The path failed to open.
3054**/
3055EFI_STATUS
3056EFIAPI
3057ShellIsFile(
3058 IN CONST CHAR16 *Name
3059 )
3060{
3061 EFI_STATUS Status;
jcarseya405b862010-09-14 05:18:09 +00003062 SHELL_FILE_HANDLE Handle;
jcarsey36a9d672009-11-20 21:13:41 +00003063
jcarseyecd3d592009-12-07 18:05:00 +00003064 ASSERT(Name != NULL);
3065
jcarsey36a9d672009-11-20 21:13:41 +00003066 Handle = NULL;
3067
3068 Status = ShellOpenFileByName(Name, &Handle, EFI_FILE_MODE_READ, 0);
3069 if (EFI_ERROR(Status)) {
3070 return (Status);
3071 }
3072
3073 if (FileHandleIsDirectory(Handle) != EFI_SUCCESS) {
3074 ShellCloseFile(&Handle);
3075 return (EFI_SUCCESS);
3076 }
3077 ShellCloseFile(&Handle);
3078 return (EFI_NOT_FOUND);
3079}
3080
3081/**
jcarseyb3011f42010-01-11 21:49:04 +00003082 Function to determine if a given filename represents a file.
3083
3084 This will search the CWD and then the Path.
3085
3086 If Name is NULL, then ASSERT.
3087
3088 @param[in] Name Path to file to test.
3089
3090 @retval EFI_SUCCESS The Path represents a file.
3091 @retval EFI_NOT_FOUND The Path does not represent a file.
3092 @retval other The path failed to open.
3093**/
3094EFI_STATUS
3095EFIAPI
3096ShellIsFileInPath(
3097 IN CONST CHAR16 *Name
jcarseya405b862010-09-14 05:18:09 +00003098 )
3099{
jcarseyb3011f42010-01-11 21:49:04 +00003100 CHAR16 *NewName;
3101 EFI_STATUS Status;
3102
3103 if (!EFI_ERROR(ShellIsFile(Name))) {
jcarseya405b862010-09-14 05:18:09 +00003104 return (EFI_SUCCESS);
jcarseyb3011f42010-01-11 21:49:04 +00003105 }
3106
3107 NewName = ShellFindFilePath(Name);
3108 if (NewName == NULL) {
3109 return (EFI_NOT_FOUND);
3110 }
3111 Status = ShellIsFile(NewName);
3112 FreePool(NewName);
3113 return (Status);
3114}
jcarsey252d9452011-03-25 20:49:53 +00003115
jcarseyb3011f42010-01-11 21:49:04 +00003116/**
Jaben Carsey74b0fb82013-11-22 21:37:34 +00003117 Function return the number converted from a hex representation of a number.
3118
3119 Note: this function cannot be used when (UINTN)(-1), (0xFFFFFFFF) may be a valid
3120 result. Use ShellConvertStringToUint64 instead.
3121
3122 @param[in] String String representation of a number.
3123
3124 @return The unsigned integer result of the conversion.
3125 @retval (UINTN)(-1) An error occured.
3126**/
3127UINTN
3128EFIAPI
3129ShellHexStrToUintn(
3130 IN CONST CHAR16 *String
3131 )
3132{
3133 UINT64 RetVal;
3134
3135 if (!EFI_ERROR(ShellConvertStringToUint64(String, &RetVal, TRUE, TRUE))) {
3136 return ((UINTN)RetVal);
3137 }
3138
3139 return ((UINTN)(-1));
3140}
3141
3142/**
jcarsey1e6e84c2010-01-25 20:05:08 +00003143 Function to determine whether a string is decimal or hex representation of a number
Jaben Carseyd59fc242013-11-14 23:52:43 +00003144 and return the number converted from the string. Spaces are always skipped.
jcarsey125c2cf2009-11-18 21:36:50 +00003145
3146 @param[in] String String representation of a number
3147
jcarsey252d9452011-03-25 20:49:53 +00003148 @return the number
3149 @retval (UINTN)(-1) An error ocurred.
jcarsey125c2cf2009-11-18 21:36:50 +00003150**/
3151UINTN
3152EFIAPI
3153ShellStrToUintn(
3154 IN CONST CHAR16 *String
3155 )
3156{
jcarsey252d9452011-03-25 20:49:53 +00003157 UINT64 RetVal;
3158 BOOLEAN Hex;
3159
3160 Hex = FALSE;
3161
jcarsey658bf432014-11-04 22:33:16 +00003162 if (!InternalShellIsHexOrDecimalNumber(String, Hex, TRUE, FALSE)) {
jcarsey252d9452011-03-25 20:49:53 +00003163 Hex = TRUE;
jcarsey125c2cf2009-11-18 21:36:50 +00003164 }
jcarsey252d9452011-03-25 20:49:53 +00003165
3166 if (!EFI_ERROR(ShellConvertStringToUint64(String, &RetVal, Hex, TRUE))) {
3167 return ((UINTN)RetVal);
3168 }
3169 return ((UINTN)(-1));
jcarsey125c2cf2009-11-18 21:36:50 +00003170}
3171
3172/**
3173 Safely append with automatic string resizing given length of Destination and
3174 desired length of copy from Source.
3175
3176 append the first D characters of Source to the end of Destination, where D is
3177 the lesser of Count and the StrLen() of Source. If appending those D characters
3178 will fit within Destination (whose Size is given as CurrentSize) and
jcarsey1e6e84c2010-01-25 20:05:08 +00003179 still leave room for a NULL terminator, then those characters are appended,
3180 starting at the original terminating NULL of Destination, and a new terminating
3181 NULL is appended.
jcarsey125c2cf2009-11-18 21:36:50 +00003182
3183 If appending D characters onto Destination will result in a overflow of the size
3184 given in CurrentSize the string will be grown such that the copy can be performed
3185 and CurrentSize will be updated to the new size.
3186
3187 If Source is NULL, there is nothing to append, just return the current buffer in
3188 Destination.
3189
3190 if Destination is NULL, then ASSERT()
3191 if Destination's current length (including NULL terminator) is already more then
3192 CurrentSize, then ASSERT()
3193
ydong104ff7e372011-09-02 08:05:34 +00003194 @param[in, out] Destination The String to append onto
3195 @param[in, out] CurrentSize on call the number of bytes in Destination. On
jcarsey125c2cf2009-11-18 21:36:50 +00003196 return possibly the new size (still in bytes). if NULL
3197 then allocate whatever is needed.
3198 @param[in] Source The String to append from
3199 @param[in] Count Maximum number of characters to append. if 0 then
3200 all are appended.
3201
3202 @return Destination return the resultant string.
3203**/
3204CHAR16*
3205EFIAPI
3206StrnCatGrow (
3207 IN OUT CHAR16 **Destination,
3208 IN OUT UINTN *CurrentSize,
3209 IN CONST CHAR16 *Source,
3210 IN UINTN Count
3211 )
3212{
3213 UINTN DestinationStartSize;
3214 UINTN NewSize;
3215
3216 //
3217 // ASSERTs
3218 //
3219 ASSERT(Destination != NULL);
3220
3221 //
3222 // If there's nothing to do then just return Destination
3223 //
3224 if (Source == NULL) {
3225 return (*Destination);
3226 }
3227
3228 //
3229 // allow for un-initialized pointers, based on size being 0
3230 //
3231 if (CurrentSize != NULL && *CurrentSize == 0) {
3232 *Destination = NULL;
3233 }
3234
3235 //
3236 // allow for NULL pointers address as Destination
3237 //
3238 if (*Destination != NULL) {
3239 ASSERT(CurrentSize != 0);
3240 DestinationStartSize = StrSize(*Destination);
3241 ASSERT(DestinationStartSize <= *CurrentSize);
3242 } else {
3243 DestinationStartSize = 0;
3244// ASSERT(*CurrentSize == 0);
3245 }
3246
3247 //
3248 // Append all of Source?
3249 //
3250 if (Count == 0) {
3251 Count = StrLen(Source);
3252 }
3253
3254 //
3255 // Test and grow if required
3256 //
3257 if (CurrentSize != NULL) {
3258 NewSize = *CurrentSize;
ydong10f480fdc2012-09-07 01:55:33 +00003259 if (NewSize < DestinationStartSize + (Count * sizeof(CHAR16))) {
3260 while (NewSize < (DestinationStartSize + (Count*sizeof(CHAR16)))) {
3261 NewSize += 2 * Count * sizeof(CHAR16);
3262 }
3263 *Destination = ReallocatePool(*CurrentSize, NewSize, *Destination);
3264 *CurrentSize = NewSize;
jcarsey125c2cf2009-11-18 21:36:50 +00003265 }
jcarsey125c2cf2009-11-18 21:36:50 +00003266 } else {
Qiu Shuminc587fd32015-07-02 01:12:03 +00003267 NewSize = (Count+1)*sizeof(CHAR16);
3268 *Destination = AllocateZeroPool(NewSize);
jcarsey125c2cf2009-11-18 21:36:50 +00003269 }
3270
3271 //
3272 // Now use standard StrnCat on a big enough buffer
3273 //
jcarseyc9d92df2010-02-03 15:37:54 +00003274 if (*Destination == NULL) {
3275 return (NULL);
3276 }
Qiu Shumine75390f2015-06-30 03:18:31 +00003277
Qiu Shuminc587fd32015-07-02 01:12:03 +00003278 StrnCatS(*Destination, NewSize/sizeof(CHAR16), Source, Count);
Qiu Shumine75390f2015-06-30 03:18:31 +00003279 return *Destination;
jcarsey125c2cf2009-11-18 21:36:50 +00003280}
jcarseyc9d92df2010-02-03 15:37:54 +00003281
3282/**
3283 Prompt the user and return the resultant answer to the requestor.
3284
3285 This function will display the requested question on the shell prompt and then
3286 wait for an apropriate answer to be input from the console.
3287
jcarseya405b862010-09-14 05:18:09 +00003288 if the SHELL_PROMPT_REQUEST_TYPE is SHELL_PROMPT_REQUEST_TYPE_YESNO, ShellPromptResponseTypeQuitContinue
jcarseyc9d92df2010-02-03 15:37:54 +00003289 or SHELL_PROMPT_REQUEST_TYPE_YESNOCANCEL then *Response is of type SHELL_PROMPT_RESPONSE.
3290
jcarseya405b862010-09-14 05:18:09 +00003291 if the SHELL_PROMPT_REQUEST_TYPE is ShellPromptResponseTypeFreeform then *Response is of type
jcarseyc9d92df2010-02-03 15:37:54 +00003292 CHAR16*.
3293
3294 In either case *Response must be callee freed if Response was not NULL;
3295
3296 @param Type What type of question is asked. This is used to filter the input
3297 to prevent invalid answers to question.
3298 @param Prompt Pointer to string prompt to use to request input.
3299 @param Response Pointer to Response which will be populated upon return.
3300
3301 @retval EFI_SUCCESS The operation was sucessful.
3302 @retval EFI_UNSUPPORTED The operation is not supported as requested.
3303 @retval EFI_INVALID_PARAMETER A parameter was invalid.
3304 @return other The operation failed.
3305**/
3306EFI_STATUS
3307EFIAPI
3308ShellPromptForResponse (
3309 IN SHELL_PROMPT_REQUEST_TYPE Type,
3310 IN CHAR16 *Prompt OPTIONAL,
3311 IN OUT VOID **Response OPTIONAL
3312 )
3313{
3314 EFI_STATUS Status;
3315 EFI_INPUT_KEY Key;
3316 UINTN EventIndex;
3317 SHELL_PROMPT_RESPONSE *Resp;
jcarseya405b862010-09-14 05:18:09 +00003318 UINTN Size;
3319 CHAR16 *Buffer;
jcarseyc9d92df2010-02-03 15:37:54 +00003320
jcarseya405b862010-09-14 05:18:09 +00003321 Status = EFI_UNSUPPORTED;
3322 Resp = NULL;
3323 Buffer = NULL;
3324 Size = 0;
3325 if (Type != ShellPromptResponseTypeFreeform) {
jcarsey252d9452011-03-25 20:49:53 +00003326 Resp = (SHELL_PROMPT_RESPONSE*)AllocateZeroPool(sizeof(SHELL_PROMPT_RESPONSE));
jcarsey3e082d52010-10-04 16:44:57 +00003327 if (Resp == NULL) {
3328 return (EFI_OUT_OF_RESOURCES);
3329 }
xdu290bfa222010-07-19 05:21:27 +00003330 }
jcarseyc9d92df2010-02-03 15:37:54 +00003331
3332 switch(Type) {
jcarseya405b862010-09-14 05:18:09 +00003333 case ShellPromptResponseTypeQuitContinue:
jcarseyc9d92df2010-02-03 15:37:54 +00003334 if (Prompt != NULL) {
3335 ShellPrintEx(-1, -1, L"%s", Prompt);
3336 }
3337 //
3338 // wait for valid response
3339 //
3340 gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &EventIndex);
3341 Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
Jaben Carsey31b018a2014-01-16 16:52:39 +00003342 if (EFI_ERROR(Status)) {
3343 break;
3344 }
jcarseyc9d92df2010-02-03 15:37:54 +00003345 ShellPrintEx(-1, -1, L"%c", Key.UnicodeChar);
3346 if (Key.UnicodeChar == L'Q' || Key.UnicodeChar ==L'q') {
jcarseya405b862010-09-14 05:18:09 +00003347 *Resp = ShellPromptResponseQuit;
jcarseyc9d92df2010-02-03 15:37:54 +00003348 } else {
jcarseya405b862010-09-14 05:18:09 +00003349 *Resp = ShellPromptResponseContinue;
jcarseyc9d92df2010-02-03 15:37:54 +00003350 }
3351 break;
jcarseya405b862010-09-14 05:18:09 +00003352 case ShellPromptResponseTypeYesNoCancel:
jcarseyc9d92df2010-02-03 15:37:54 +00003353 if (Prompt != NULL) {
3354 ShellPrintEx(-1, -1, L"%s", Prompt);
3355 }
3356 //
3357 // wait for valid response
3358 //
jcarseya405b862010-09-14 05:18:09 +00003359 *Resp = ShellPromptResponseMax;
3360 while (*Resp == ShellPromptResponseMax) {
Jaben Carsey194ae482013-12-09 22:55:13 +00003361 if (ShellGetExecutionBreakFlag()) {
3362 Status = EFI_ABORTED;
3363 break;
3364 }
jcarseyc9d92df2010-02-03 15:37:54 +00003365 gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &EventIndex);
3366 Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
Jaben Carsey31b018a2014-01-16 16:52:39 +00003367 if (EFI_ERROR(Status)) {
3368 break;
3369 }
jcarseyc9d92df2010-02-03 15:37:54 +00003370 ShellPrintEx(-1, -1, L"%c", Key.UnicodeChar);
3371 switch (Key.UnicodeChar) {
3372 case L'Y':
3373 case L'y':
jcarseya405b862010-09-14 05:18:09 +00003374 *Resp = ShellPromptResponseYes;
jcarseyc9d92df2010-02-03 15:37:54 +00003375 break;
3376 case L'N':
3377 case L'n':
jcarseya405b862010-09-14 05:18:09 +00003378 *Resp = ShellPromptResponseNo;
jcarseyc9d92df2010-02-03 15:37:54 +00003379 break;
3380 case L'C':
3381 case L'c':
jcarseya405b862010-09-14 05:18:09 +00003382 *Resp = ShellPromptResponseCancel;
3383 break;
3384 }
3385 }
3386 break; case ShellPromptResponseTypeYesNoAllCancel:
3387 if (Prompt != NULL) {
3388 ShellPrintEx(-1, -1, L"%s", Prompt);
3389 }
3390 //
3391 // wait for valid response
3392 //
3393 *Resp = ShellPromptResponseMax;
3394 while (*Resp == ShellPromptResponseMax) {
Jaben Carsey194ae482013-12-09 22:55:13 +00003395 if (ShellGetExecutionBreakFlag()) {
3396 Status = EFI_ABORTED;
3397 break;
3398 }
jcarseya405b862010-09-14 05:18:09 +00003399 gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &EventIndex);
3400 Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
Jaben Carsey31b018a2014-01-16 16:52:39 +00003401 if (EFI_ERROR(Status)) {
3402 break;
3403 }
jcarseya405b862010-09-14 05:18:09 +00003404 ShellPrintEx(-1, -1, L"%c", Key.UnicodeChar);
3405 switch (Key.UnicodeChar) {
3406 case L'Y':
3407 case L'y':
3408 *Resp = ShellPromptResponseYes;
3409 break;
3410 case L'N':
3411 case L'n':
3412 *Resp = ShellPromptResponseNo;
3413 break;
3414 case L'A':
3415 case L'a':
3416 *Resp = ShellPromptResponseAll;
3417 break;
3418 case L'C':
3419 case L'c':
3420 *Resp = ShellPromptResponseCancel;
jcarseyc9d92df2010-02-03 15:37:54 +00003421 break;
3422 }
3423 }
3424 break;
jcarseya405b862010-09-14 05:18:09 +00003425 case ShellPromptResponseTypeEnterContinue:
3426 case ShellPromptResponseTypeAnyKeyContinue:
jcarseyc9d92df2010-02-03 15:37:54 +00003427 if (Prompt != NULL) {
3428 ShellPrintEx(-1, -1, L"%s", Prompt);
3429 }
3430 //
3431 // wait for valid response
3432 //
jcarseya405b862010-09-14 05:18:09 +00003433 *Resp = ShellPromptResponseMax;
3434 while (*Resp == ShellPromptResponseMax) {
Jaben Carsey194ae482013-12-09 22:55:13 +00003435 if (ShellGetExecutionBreakFlag()) {
3436 Status = EFI_ABORTED;
3437 break;
3438 }
jcarseyc9d92df2010-02-03 15:37:54 +00003439 gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &EventIndex);
jcarseya405b862010-09-14 05:18:09 +00003440 if (Type == ShellPromptResponseTypeEnterContinue) {
jcarseyc9d92df2010-02-03 15:37:54 +00003441 Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
Jaben Carsey31b018a2014-01-16 16:52:39 +00003442 if (EFI_ERROR(Status)) {
3443 break;
3444 }
jcarseyc9d92df2010-02-03 15:37:54 +00003445 ShellPrintEx(-1, -1, L"%c", Key.UnicodeChar);
3446 if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {
jcarseya405b862010-09-14 05:18:09 +00003447 *Resp = ShellPromptResponseContinue;
jcarseyc9d92df2010-02-03 15:37:54 +00003448 break;
3449 }
3450 }
jcarseya405b862010-09-14 05:18:09 +00003451 if (Type == ShellPromptResponseTypeAnyKeyContinue) {
3452 Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
3453 ASSERT_EFI_ERROR(Status);
3454 *Resp = ShellPromptResponseContinue;
jcarseyc9d92df2010-02-03 15:37:54 +00003455 break;
3456 }
3457 }
3458 break;
jcarseya405b862010-09-14 05:18:09 +00003459 case ShellPromptResponseTypeYesNo:
3460 if (Prompt != NULL) {
3461 ShellPrintEx(-1, -1, L"%s", Prompt);
3462 }
3463 //
3464 // wait for valid response
3465 //
3466 *Resp = ShellPromptResponseMax;
3467 while (*Resp == ShellPromptResponseMax) {
Jaben Carsey194ae482013-12-09 22:55:13 +00003468 if (ShellGetExecutionBreakFlag()) {
3469 Status = EFI_ABORTED;
3470 break;
3471 }
jcarseya405b862010-09-14 05:18:09 +00003472 gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &EventIndex);
3473 Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
Jaben Carsey31b018a2014-01-16 16:52:39 +00003474 if (EFI_ERROR(Status)) {
3475 break;
3476 }
jcarseya405b862010-09-14 05:18:09 +00003477 ShellPrintEx(-1, -1, L"%c", Key.UnicodeChar);
3478 switch (Key.UnicodeChar) {
3479 case L'Y':
3480 case L'y':
3481 *Resp = ShellPromptResponseYes;
3482 break;
3483 case L'N':
3484 case L'n':
3485 *Resp = ShellPromptResponseNo;
3486 break;
3487 }
3488 }
3489 break;
3490 case ShellPromptResponseTypeFreeform:
3491 if (Prompt != NULL) {
3492 ShellPrintEx(-1, -1, L"%s", Prompt);
3493 }
3494 while(1) {
Jaben Carsey194ae482013-12-09 22:55:13 +00003495 if (ShellGetExecutionBreakFlag()) {
3496 Status = EFI_ABORTED;
3497 break;
3498 }
jcarseya405b862010-09-14 05:18:09 +00003499 gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &EventIndex);
3500 Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
Jaben Carsey31b018a2014-01-16 16:52:39 +00003501 if (EFI_ERROR(Status)) {
3502 break;
3503 }
jcarseya405b862010-09-14 05:18:09 +00003504 ShellPrintEx(-1, -1, L"%c", Key.UnicodeChar);
3505 if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {
3506 break;
3507 }
3508 ASSERT((Buffer == NULL && Size == 0) || (Buffer != NULL));
3509 StrnCatGrow(&Buffer, &Size, &Key.UnicodeChar, 1);
3510 }
3511 break;
3512 //
3513 // This is the location to add new prompt types.
Jaben Carsey194ae482013-12-09 22:55:13 +00003514 // If your new type loops remember to add ExecutionBreak support.
jcarseya405b862010-09-14 05:18:09 +00003515 //
jcarseyc9d92df2010-02-03 15:37:54 +00003516 default:
jcarseya405b862010-09-14 05:18:09 +00003517 ASSERT(FALSE);
jcarseyc9d92df2010-02-03 15:37:54 +00003518 }
3519
3520 if (Response != NULL) {
jcarseya405b862010-09-14 05:18:09 +00003521 if (Resp != NULL) {
3522 *Response = Resp;
3523 } else if (Buffer != NULL) {
3524 *Response = Buffer;
3525 }
jcarseyc9d92df2010-02-03 15:37:54 +00003526 } else {
jcarseya405b862010-09-14 05:18:09 +00003527 if (Resp != NULL) {
3528 FreePool(Resp);
3529 }
3530 if (Buffer != NULL) {
3531 FreePool(Buffer);
3532 }
jcarseyc9d92df2010-02-03 15:37:54 +00003533 }
3534
jcarseya405b862010-09-14 05:18:09 +00003535 ShellPrintEx(-1, -1, L"\r\n");
jcarseyc9d92df2010-02-03 15:37:54 +00003536 return (Status);
3537}
3538
3539/**
3540 Prompt the user and return the resultant answer to the requestor.
3541
3542 This function is the same as ShellPromptForResponse, except that the prompt is
3543 automatically pulled from HII.
3544
3545 @param Type What type of question is asked. This is used to filter the input
3546 to prevent invalid answers to question.
jcarseya405b862010-09-14 05:18:09 +00003547 @param[in] HiiFormatStringId The format string Id for getting from Hii.
3548 @param[in] HiiFormatHandle The format string Handle for getting from Hii.
3549 @param Response Pointer to Response which will be populated upon return.
jcarseyc9d92df2010-02-03 15:37:54 +00003550
3551 @retval EFI_SUCCESS the operation was sucessful.
3552 @return other the operation failed.
3553
3554 @sa ShellPromptForResponse
3555**/
3556EFI_STATUS
3557EFIAPI
3558ShellPromptForResponseHii (
3559 IN SHELL_PROMPT_REQUEST_TYPE Type,
3560 IN CONST EFI_STRING_ID HiiFormatStringId,
3561 IN CONST EFI_HANDLE HiiFormatHandle,
3562 IN OUT VOID **Response
3563 )
3564{
3565 CHAR16 *Prompt;
3566 EFI_STATUS Status;
3567
3568 Prompt = HiiGetString(HiiFormatHandle, HiiFormatStringId, NULL);
3569 Status = ShellPromptForResponse(Type, Prompt, Response);
3570 FreePool(Prompt);
3571 return (Status);
3572}
3573
jcarseya405b862010-09-14 05:18:09 +00003574/**
3575 Function to determin if an entire string is a valid number.
jcarseyc9d92df2010-02-03 15:37:54 +00003576
jcarseya405b862010-09-14 05:18:09 +00003577 If Hex it must be preceeded with a 0x or has ForceHex, set TRUE.
3578
3579 @param[in] String The string to evaluate.
3580 @param[in] ForceHex TRUE - always assume hex.
3581 @param[in] StopAtSpace TRUE to halt upon finding a space, FALSE to keep going.
jcarsey658bf432014-11-04 22:33:16 +00003582 @param[in] TimeNumbers TRUE to allow numbers with ":", FALSE otherwise.
jcarseya405b862010-09-14 05:18:09 +00003583
3584 @retval TRUE It is all numeric (dec/hex) characters.
3585 @retval FALSE There is a non-numeric character.
3586**/
3587BOOLEAN
3588EFIAPI
jcarsey252d9452011-03-25 20:49:53 +00003589InternalShellIsHexOrDecimalNumber (
jcarseya405b862010-09-14 05:18:09 +00003590 IN CONST CHAR16 *String,
3591 IN CONST BOOLEAN ForceHex,
jcarsey658bf432014-11-04 22:33:16 +00003592 IN CONST BOOLEAN StopAtSpace,
3593 IN CONST BOOLEAN TimeNumbers
jcarseya405b862010-09-14 05:18:09 +00003594 )
3595{
3596 BOOLEAN Hex;
3597
3598 //
3599 // chop off a single negative sign
3600 //
3601 if (String != NULL && *String == L'-') {
3602 String++;
3603 }
darylm503b0934ac2011-11-12 00:35:11 +00003604
jcarseya405b862010-09-14 05:18:09 +00003605 if (String == NULL) {
3606 return (FALSE);
3607 }
3608
3609 //
3610 // chop leading zeroes
3611 //
3612 while(String != NULL && *String == L'0'){
3613 String++;
3614 }
3615 //
3616 // allow '0x' or '0X', but not 'x' or 'X'
3617 //
3618 if (String != NULL && (*String == L'x' || *String == L'X')) {
3619 if (*(String-1) != L'0') {
3620 //
3621 // we got an x without a preceeding 0
3622 //
3623 return (FALSE);
3624 }
3625 String++;
3626 Hex = TRUE;
3627 } else if (ForceHex) {
3628 Hex = TRUE;
3629 } else {
3630 Hex = FALSE;
3631 }
3632
3633 //
3634 // loop through the remaining characters and use the lib function
3635 //
3636 for ( ; String != NULL && *String != CHAR_NULL && !(StopAtSpace && *String == L' ') ; String++){
jcarsey658bf432014-11-04 22:33:16 +00003637 if (TimeNumbers && (String[0] == L':')) {
3638 continue;
3639 }
jcarseya405b862010-09-14 05:18:09 +00003640 if (Hex) {
3641 if (!ShellIsHexaDecimalDigitCharacter(*String)) {
3642 return (FALSE);
3643 }
3644 } else {
3645 if (!ShellIsDecimalDigitCharacter(*String)) {
3646 return (FALSE);
3647 }
3648 }
3649 }
jcarsey252d9452011-03-25 20:49:53 +00003650
jcarseya405b862010-09-14 05:18:09 +00003651 return (TRUE);
3652}
3653
3654/**
3655 Function to determine if a given filename exists.
3656
3657 @param[in] Name Path to test.
3658
3659 @retval EFI_SUCCESS The Path represents a file.
3660 @retval EFI_NOT_FOUND The Path does not represent a file.
3661 @retval other The path failed to open.
3662**/
3663EFI_STATUS
3664EFIAPI
3665ShellFileExists(
3666 IN CONST CHAR16 *Name
3667 )
3668{
3669 EFI_STATUS Status;
3670 EFI_SHELL_FILE_INFO *List;
3671
3672 ASSERT(Name != NULL);
3673
3674 List = NULL;
3675 Status = ShellOpenFileMetaArg((CHAR16*)Name, EFI_FILE_MODE_READ, &List);
3676 if (EFI_ERROR(Status)) {
3677 return (Status);
3678 }
3679
3680 ShellCloseFileMetaArg(&List);
3681
3682 return (EFI_SUCCESS);
3683}
jcarsey252d9452011-03-25 20:49:53 +00003684
3685/**
darylm503b0934ac2011-11-12 00:35:11 +00003686 Convert a Unicode character to upper case only if
jcarsey252d9452011-03-25 20:49:53 +00003687 it maps to a valid small-case ASCII character.
3688
3689 This internal function only deal with Unicode character
3690 which maps to a valid small-case ASCII character, i.e.
3691 L'a' to L'z'. For other Unicode character, the input character
3692 is returned directly.
3693
3694 @param Char The character to convert.
3695
3696 @retval LowerCharacter If the Char is with range L'a' to L'z'.
3697 @retval Unchanged Otherwise.
3698
3699**/
3700CHAR16
3701EFIAPI
3702InternalShellCharToUpper (
3703 IN CHAR16 Char
3704 )
3705{
3706 if (Char >= L'a' && Char <= L'z') {
3707 return (CHAR16) (Char - (L'a' - L'A'));
3708 }
3709
3710 return Char;
3711}
3712
3713/**
3714 Convert a Unicode character to numerical value.
3715
3716 This internal function only deal with Unicode character
3717 which maps to a valid hexadecimal ASII character, i.e.
darylm503b0934ac2011-11-12 00:35:11 +00003718 L'0' to L'9', L'a' to L'f' or L'A' to L'F'. For other
jcarsey252d9452011-03-25 20:49:53 +00003719 Unicode character, the value returned does not make sense.
3720
3721 @param Char The character to convert.
3722
3723 @return The numerical value converted.
3724
3725**/
3726UINTN
3727EFIAPI
3728InternalShellHexCharToUintn (
3729 IN CHAR16 Char
3730 )
3731{
3732 if (ShellIsDecimalDigitCharacter (Char)) {
3733 return Char - L'0';
3734 }
3735
3736 return (UINTN) (10 + InternalShellCharToUpper (Char) - L'A');
3737}
3738
3739/**
3740 Convert a Null-terminated Unicode hexadecimal string to a value of type UINT64.
3741
Jaben Carsey80f3e342015-07-02 17:26:42 +00003742 This function returns a value of type UINT64 by interpreting the contents
jcarsey252d9452011-03-25 20:49:53 +00003743 of the Unicode string specified by String as a hexadecimal number.
3744 The format of the input Unicode string String is:
3745
3746 [spaces][zeros][x][hexadecimal digits].
3747
3748 The valid hexadecimal digit character is in the range [0-9], [a-f] and [A-F].
3749 The prefix "0x" is optional. Both "x" and "X" is allowed in "0x" prefix.
3750 If "x" appears in the input string, it must be prefixed with at least one 0.
3751 The function will ignore the pad space, which includes spaces or tab characters,
3752 before [zeros], [x] or [hexadecimal digit]. The running zero before [x] or
3753 [hexadecimal digit] will be ignored. Then, the decoding starts after [x] or the
3754 first valid hexadecimal digit. Then, the function stops at the first character that is
3755 a not a valid hexadecimal character or NULL, whichever one comes first.
3756
3757 If String has only pad spaces, then zero is returned.
3758 If String has no leading pad spaces, leading zeros or valid hexadecimal digits,
3759 then zero is returned.
3760
3761 @param[in] String A pointer to a Null-terminated Unicode string.
3762 @param[out] Value Upon a successful return the value of the conversion.
3763 @param[in] StopAtSpace FALSE to skip spaces.
3764
3765 @retval EFI_SUCCESS The conversion was successful.
3766 @retval EFI_INVALID_PARAMETER A parameter was NULL or invalid.
3767 @retval EFI_DEVICE_ERROR An overflow occured.
3768**/
3769EFI_STATUS
3770EFIAPI
3771InternalShellStrHexToUint64 (
3772 IN CONST CHAR16 *String,
3773 OUT UINT64 *Value,
3774 IN CONST BOOLEAN StopAtSpace
3775 )
3776{
3777 UINT64 Result;
3778
3779 if (String == NULL || StrSize(String) == 0 || Value == NULL) {
3780 return (EFI_INVALID_PARAMETER);
3781 }
darylm503b0934ac2011-11-12 00:35:11 +00003782
jcarsey252d9452011-03-25 20:49:53 +00003783 //
darylm503b0934ac2011-11-12 00:35:11 +00003784 // Ignore the pad spaces (space or tab)
jcarsey252d9452011-03-25 20:49:53 +00003785 //
3786 while ((*String == L' ') || (*String == L'\t')) {
3787 String++;
3788 }
3789
3790 //
3791 // Ignore leading Zeros after the spaces
3792 //
3793 while (*String == L'0') {
3794 String++;
3795 }
3796
3797 if (InternalShellCharToUpper (*String) == L'X') {
3798 if (*(String - 1) != L'0') {
3799 return 0;
3800 }
3801 //
3802 // Skip the 'X'
3803 //
3804 String++;
3805 }
3806
3807 Result = 0;
darylm503b0934ac2011-11-12 00:35:11 +00003808
jcarsey252d9452011-03-25 20:49:53 +00003809 //
Jaben Carsey80f3e342015-07-02 17:26:42 +00003810 // there is a space where there should't be
jcarsey252d9452011-03-25 20:49:53 +00003811 //
Jaben Carsey80f3e342015-07-02 17:26:42 +00003812 if (*String == L' ') {
3813 return (EFI_INVALID_PARAMETER);
jcarsey252d9452011-03-25 20:49:53 +00003814 }
darylm503b0934ac2011-11-12 00:35:11 +00003815
jcarsey252d9452011-03-25 20:49:53 +00003816 while (ShellIsHexaDecimalDigitCharacter (*String)) {
3817 //
darylm503b0934ac2011-11-12 00:35:11 +00003818 // If the Hex Number represented by String overflows according
Jaben Carsey80f3e342015-07-02 17:26:42 +00003819 // to the range defined by UINT64, then return EFI_DEVICE_ERROR.
jcarsey252d9452011-03-25 20:49:53 +00003820 //
3821 if (!(Result <= (RShiftU64((((UINT64) ~0) - InternalShellHexCharToUintn (*String)), 4)))) {
3822// if (!(Result <= ((((UINT64) ~0) - InternalShellHexCharToUintn (*String)) >> 4))) {
3823 return (EFI_DEVICE_ERROR);
3824 }
3825
3826 Result = (LShiftU64(Result, 4));
3827 Result += InternalShellHexCharToUintn (*String);
3828 String++;
3829
3830 //
jcarsey49bd4982012-01-27 18:42:43 +00003831 // stop at spaces if requested
jcarsey252d9452011-03-25 20:49:53 +00003832 //
jcarsey49bd4982012-01-27 18:42:43 +00003833 if (StopAtSpace && *String == L' ') {
3834 break;
jcarsey252d9452011-03-25 20:49:53 +00003835 }
3836 }
3837
3838 *Value = Result;
3839 return (EFI_SUCCESS);
3840}
3841
3842/**
3843 Convert a Null-terminated Unicode decimal string to a value of
3844 type UINT64.
3845
3846 This function returns a value of type UINT64 by interpreting the contents
3847 of the Unicode string specified by String as a decimal number. The format
3848 of the input Unicode string String is:
3849
3850 [spaces] [decimal digits].
3851
3852 The valid decimal digit character is in the range [0-9]. The
3853 function will ignore the pad space, which includes spaces or
3854 tab characters, before [decimal digits]. The running zero in the
3855 beginning of [decimal digits] will be ignored. Then, the function
3856 stops at the first character that is a not a valid decimal character
3857 or a Null-terminator, whichever one comes first.
3858
3859 If String has only pad spaces, then 0 is returned.
3860 If String has no pad spaces or valid decimal digits,
3861 then 0 is returned.
3862
3863 @param[in] String A pointer to a Null-terminated Unicode string.
3864 @param[out] Value Upon a successful return the value of the conversion.
3865 @param[in] StopAtSpace FALSE to skip spaces.
3866
3867 @retval EFI_SUCCESS The conversion was successful.
3868 @retval EFI_INVALID_PARAMETER A parameter was NULL or invalid.
3869 @retval EFI_DEVICE_ERROR An overflow occured.
3870**/
3871EFI_STATUS
3872EFIAPI
3873InternalShellStrDecimalToUint64 (
3874 IN CONST CHAR16 *String,
3875 OUT UINT64 *Value,
3876 IN CONST BOOLEAN StopAtSpace
3877 )
3878{
3879 UINT64 Result;
3880
3881 if (String == NULL || StrSize (String) == 0 || Value == NULL) {
3882 return (EFI_INVALID_PARAMETER);
3883 }
3884
3885 //
3886 // Ignore the pad spaces (space or tab)
3887 //
3888 while ((*String == L' ') || (*String == L'\t')) {
3889 String++;
3890 }
3891
3892 //
3893 // Ignore leading Zeros after the spaces
3894 //
3895 while (*String == L'0') {
3896 String++;
3897 }
3898
3899 Result = 0;
3900
3901 //
Jaben Carsey80f3e342015-07-02 17:26:42 +00003902 // Stop upon space if requested
3903 // (if the whole value was 0)
jcarsey252d9452011-03-25 20:49:53 +00003904 //
Jaben Carsey80f3e342015-07-02 17:26:42 +00003905 if (StopAtSpace && *String == L' ') {
3906 *Value = Result;
3907 return (EFI_SUCCESS);
jcarsey252d9452011-03-25 20:49:53 +00003908 }
Jaben Carsey80f3e342015-07-02 17:26:42 +00003909
jcarsey252d9452011-03-25 20:49:53 +00003910 while (ShellIsDecimalDigitCharacter (*String)) {
3911 //
darylm503b0934ac2011-11-12 00:35:11 +00003912 // If the number represented by String overflows according
Jaben Carsey80f3e342015-07-02 17:26:42 +00003913 // to the range defined by UINT64, then return EFI_DEVICE_ERROR.
jcarsey252d9452011-03-25 20:49:53 +00003914 //
darylm503b0934ac2011-11-12 00:35:11 +00003915
jcarsey252d9452011-03-25 20:49:53 +00003916 if (!(Result <= (DivU64x32((((UINT64) ~0) - (*String - L'0')),10)))) {
3917 return (EFI_DEVICE_ERROR);
3918 }
3919
3920 Result = MultU64x32(Result, 10) + (*String - L'0');
3921 String++;
3922
3923 //
3924 // Stop at spaces if requested
3925 //
3926 if (StopAtSpace && *String == L' ') {
3927 break;
3928 }
3929 }
3930
3931 *Value = Result;
darylm503b0934ac2011-11-12 00:35:11 +00003932
jcarsey252d9452011-03-25 20:49:53 +00003933 return (EFI_SUCCESS);
3934}
3935
3936/**
3937 Function to verify and convert a string to its numerical value.
3938
3939 If Hex it must be preceeded with a 0x, 0X, or has ForceHex set TRUE.
3940
3941 @param[in] String The string to evaluate.
3942 @param[out] Value Upon a successful return the value of the conversion.
3943 @param[in] ForceHex TRUE - always assume hex.
3944 @param[in] StopAtSpace FALSE to skip spaces.
darylm503b0934ac2011-11-12 00:35:11 +00003945
jcarsey252d9452011-03-25 20:49:53 +00003946 @retval EFI_SUCCESS The conversion was successful.
3947 @retval EFI_INVALID_PARAMETER String contained an invalid character.
3948 @retval EFI_NOT_FOUND String was a number, but Value was NULL.
3949**/
3950EFI_STATUS
3951EFIAPI
3952ShellConvertStringToUint64(
3953 IN CONST CHAR16 *String,
3954 OUT UINT64 *Value,
3955 IN CONST BOOLEAN ForceHex,
3956 IN CONST BOOLEAN StopAtSpace
3957 )
3958{
3959 UINT64 RetVal;
3960 CONST CHAR16 *Walker;
3961 EFI_STATUS Status;
3962 BOOLEAN Hex;
3963
3964 Hex = ForceHex;
3965
jcarsey658bf432014-11-04 22:33:16 +00003966 if (!InternalShellIsHexOrDecimalNumber(String, Hex, StopAtSpace, FALSE)) {
jcarsey252d9452011-03-25 20:49:53 +00003967 if (!Hex) {
3968 Hex = TRUE;
jcarsey658bf432014-11-04 22:33:16 +00003969 if (!InternalShellIsHexOrDecimalNumber(String, Hex, StopAtSpace, FALSE)) {
jcarsey252d9452011-03-25 20:49:53 +00003970 return (EFI_INVALID_PARAMETER);
3971 }
3972 } else {
3973 return (EFI_INVALID_PARAMETER);
3974 }
3975 }
3976
3977 //
3978 // Chop off leading spaces
3979 //
3980 for (Walker = String; Walker != NULL && *Walker != CHAR_NULL && *Walker == L' '; Walker++);
3981
3982 //
3983 // make sure we have something left that is numeric.
3984 //
jcarsey658bf432014-11-04 22:33:16 +00003985 if (Walker == NULL || *Walker == CHAR_NULL || !InternalShellIsHexOrDecimalNumber(Walker, Hex, StopAtSpace, FALSE)) {
jcarsey252d9452011-03-25 20:49:53 +00003986 return (EFI_INVALID_PARAMETER);
darylm503b0934ac2011-11-12 00:35:11 +00003987 }
jcarsey252d9452011-03-25 20:49:53 +00003988
3989 //
3990 // do the conversion.
3991 //
3992 if (Hex || StrnCmp(Walker, L"0x", 2) == 0 || StrnCmp(Walker, L"0X", 2) == 0){
3993 Status = InternalShellStrHexToUint64(Walker, &RetVal, StopAtSpace);
3994 } else {
3995 Status = InternalShellStrDecimalToUint64(Walker, &RetVal, StopAtSpace);
3996 }
3997
3998 if (Value == NULL && !EFI_ERROR(Status)) {
3999 return (EFI_NOT_FOUND);
4000 }
4001
4002 if (Value != NULL) {
4003 *Value = RetVal;
4004 }
4005
4006 return (Status);
4007}
4008
4009/**
4010 Function to determin if an entire string is a valid number.
4011
4012 If Hex it must be preceeded with a 0x or has ForceHex, set TRUE.
4013
4014 @param[in] String The string to evaluate.
4015 @param[in] ForceHex TRUE - always assume hex.
4016 @param[in] StopAtSpace TRUE to halt upon finding a space, FALSE to keep going.
4017
4018 @retval TRUE It is all numeric (dec/hex) characters.
4019 @retval FALSE There is a non-numeric character.
4020**/
4021BOOLEAN
4022EFIAPI
4023ShellIsHexOrDecimalNumber (
4024 IN CONST CHAR16 *String,
4025 IN CONST BOOLEAN ForceHex,
4026 IN CONST BOOLEAN StopAtSpace
4027 )
4028{
4029 if (ShellConvertStringToUint64(String, NULL, ForceHex, StopAtSpace) == EFI_NOT_FOUND) {
4030 return (TRUE);
4031 }
4032 return (FALSE);
4033}
jcarsey4d0a4fc2011-07-06 22:28:36 +00004034
4035/**
4036 Function to read a single line from a SHELL_FILE_HANDLE. The \n is not included in the returned
4037 buffer. The returned buffer must be callee freed.
4038
4039 If the position upon start is 0, then the Ascii Boolean will be set. This should be
4040 maintained and not changed for all operations with the same file.
4041
ydong104ff7e372011-09-02 08:05:34 +00004042 @param[in] Handle SHELL_FILE_HANDLE to read from.
4043 @param[in, out] Ascii Boolean value for indicating whether the file is
4044 Ascii (TRUE) or UCS2 (FALSE).
jcarsey4d0a4fc2011-07-06 22:28:36 +00004045
jcarseybeab0fc2011-10-10 17:26:25 +00004046 @return The line of text from the file.
4047 @retval NULL There was not enough memory available.
jcarsey4d0a4fc2011-07-06 22:28:36 +00004048
4049 @sa ShellFileHandleReadLine
4050**/
4051CHAR16*
4052EFIAPI
4053ShellFileHandleReturnLine(
4054 IN SHELL_FILE_HANDLE Handle,
4055 IN OUT BOOLEAN *Ascii
4056 )
4057{
4058 CHAR16 *RetVal;
4059 UINTN Size;
4060 EFI_STATUS Status;
4061
4062 Size = 0;
4063 RetVal = NULL;
4064
4065 Status = ShellFileHandleReadLine(Handle, RetVal, &Size, FALSE, Ascii);
4066 if (Status == EFI_BUFFER_TOO_SMALL) {
4067 RetVal = AllocateZeroPool(Size);
jcarseybeab0fc2011-10-10 17:26:25 +00004068 if (RetVal == NULL) {
4069 return (NULL);
4070 }
jcarsey4d0a4fc2011-07-06 22:28:36 +00004071 Status = ShellFileHandleReadLine(Handle, RetVal, &Size, FALSE, Ascii);
darylm503b0934ac2011-11-12 00:35:11 +00004072
jcarsey4d0a4fc2011-07-06 22:28:36 +00004073 }
jcarsey4d0a4fc2011-07-06 22:28:36 +00004074 if (EFI_ERROR(Status) && (RetVal != NULL)) {
4075 FreePool(RetVal);
4076 RetVal = NULL;
4077 }
4078 return (RetVal);
4079}
4080
4081/**
4082 Function to read a single line (up to but not including the \n) from a SHELL_FILE_HANDLE.
4083
4084 If the position upon start is 0, then the Ascii Boolean will be set. This should be
4085 maintained and not changed for all operations with the same file.
4086
ydong104ff7e372011-09-02 08:05:34 +00004087 @param[in] Handle SHELL_FILE_HANDLE to read from.
4088 @param[in, out] Buffer The pointer to buffer to read into.
4089 @param[in, out] Size The pointer to number of bytes in Buffer.
4090 @param[in] Truncate If the buffer is large enough, this has no effect.
4091 If the buffer is is too small and Truncate is TRUE,
4092 the line will be truncated.
4093 If the buffer is is too small and Truncate is FALSE,
4094 then no read will occur.
jcarsey4d0a4fc2011-07-06 22:28:36 +00004095
ydong104ff7e372011-09-02 08:05:34 +00004096 @param[in, out] Ascii Boolean value for indicating whether the file is
4097 Ascii (TRUE) or UCS2 (FALSE).
jcarsey4d0a4fc2011-07-06 22:28:36 +00004098
4099 @retval EFI_SUCCESS The operation was successful. The line is stored in
4100 Buffer.
jaben carsey9ed21942016-02-08 15:59:04 -08004101 @retval EFI_END_OF_FILE There are no more lines in the file.
jcarsey4d0a4fc2011-07-06 22:28:36 +00004102 @retval EFI_INVALID_PARAMETER Handle was NULL.
4103 @retval EFI_INVALID_PARAMETER Size was NULL.
4104 @retval EFI_BUFFER_TOO_SMALL Size was not large enough to store the line.
4105 Size was updated to the minimum space required.
4106**/
4107EFI_STATUS
4108EFIAPI
4109ShellFileHandleReadLine(
4110 IN SHELL_FILE_HANDLE Handle,
4111 IN OUT CHAR16 *Buffer,
4112 IN OUT UINTN *Size,
4113 IN BOOLEAN Truncate,
4114 IN OUT BOOLEAN *Ascii
4115 )
4116{
4117 EFI_STATUS Status;
4118 CHAR16 CharBuffer;
4119 UINTN CharSize;
4120 UINTN CountSoFar;
4121 UINT64 OriginalFilePosition;
4122
4123
4124 if (Handle == NULL
4125 ||Size == NULL
4126 ){
4127 return (EFI_INVALID_PARAMETER);
4128 }
4129 if (Buffer == NULL) {
4130 ASSERT(*Size == 0);
4131 } else {
4132 *Buffer = CHAR_NULL;
4133 }
4134 gEfiShellProtocol->GetFilePosition(Handle, &OriginalFilePosition);
4135 if (OriginalFilePosition == 0) {
4136 CharSize = sizeof(CHAR16);
4137 Status = gEfiShellProtocol->ReadFile(Handle, &CharSize, &CharBuffer);
4138 ASSERT_EFI_ERROR(Status);
4139 if (CharBuffer == gUnicodeFileTag) {
4140 *Ascii = FALSE;
4141 } else {
4142 *Ascii = TRUE;
4143 gEfiShellProtocol->SetFilePosition(Handle, OriginalFilePosition);
4144 }
4145 }
4146
jaben carsey9ed21942016-02-08 15:59:04 -08004147 if (*Ascii) {
4148 CharSize = sizeof(CHAR8);
4149 } else {
4150 CharSize = sizeof(CHAR16);
4151 }
jcarsey4d0a4fc2011-07-06 22:28:36 +00004152 for (CountSoFar = 0;;CountSoFar++){
4153 CharBuffer = 0;
jcarsey4d0a4fc2011-07-06 22:28:36 +00004154 Status = gEfiShellProtocol->ReadFile(Handle, &CharSize, &CharBuffer);
4155 if ( EFI_ERROR(Status)
4156 || CharSize == 0
4157 || (CharBuffer == L'\n' && !(*Ascii))
4158 || (CharBuffer == '\n' && *Ascii)
4159 ){
jaben carsey9ed21942016-02-08 15:59:04 -08004160 if (CharSize == 0) {
4161 Status = EFI_END_OF_FILE;
4162 }
jcarsey4d0a4fc2011-07-06 22:28:36 +00004163 break;
4164 }
4165 //
4166 // if we have space save it...
4167 //
jaben carsey9ed21942016-02-08 15:59:04 -08004168 if ((CountSoFar + 1) * CharSize < *Size){
jcarsey4d0a4fc2011-07-06 22:28:36 +00004169 ASSERT(Buffer != NULL);
jaben carsey9ed21942016-02-08 15:59:04 -08004170 if (*Ascii) {
4171 ((CHAR8*)Buffer)[CountSoFar] = (CHAR8) CharBuffer;
4172 ((CHAR8*)Buffer)[CountSoFar+1] = '\0';
4173 }
4174 else {
4175 ((CHAR16*)Buffer)[CountSoFar] = CharBuffer;
4176 ((CHAR16*)Buffer)[CountSoFar+1] = CHAR_NULL;
4177 }
jcarsey4d0a4fc2011-07-06 22:28:36 +00004178 }
4179 }
4180
4181 //
4182 // if we ran out of space tell when...
4183 //
jaben carsey9ed21942016-02-08 15:59:04 -08004184 if (Status != EFI_END_OF_FILE){
4185 if ((CountSoFar + 1) * CharSize > *Size){
4186 *Size = (CountSoFar + 1) * CharSize;
4187 if (!Truncate) {
4188 gEfiShellProtocol->SetFilePosition(Handle, OriginalFilePosition);
4189 } else {
4190 DEBUG((DEBUG_WARN, "The line was truncated in ShellFileHandleReadLine"));
4191 }
4192 return (EFI_BUFFER_TOO_SMALL);
jcarsey4d0a4fc2011-07-06 22:28:36 +00004193 }
jaben carsey9ed21942016-02-08 15:59:04 -08004194
4195 if (*Ascii) {
4196 if (CountSoFar && ((CHAR8*)Buffer)[CountSoFar - 1] == '\r') {
4197 ((CHAR8*)Buffer)[CountSoFar - 1] = '\0';
4198 }
4199 }
4200 else {
4201 if (CountSoFar && Buffer[CountSoFar - 1] == L'\r') {
4202 Buffer[CountSoFar - 1] = CHAR_NULL;
4203 }
4204 }
jcarsey4d0a4fc2011-07-06 22:28:36 +00004205 }
4206
4207 return (Status);
4208}
jcarseyfb5278e2013-02-20 18:21:14 +00004209
4210/**
jcarsey365aa982013-03-04 21:54:02 +00004211 Function to print help file / man page content in the spec from the UEFI Shell protocol GetHelpText function.
4212
4213 @param[in] CommandToGetHelpOn Pointer to a string containing the command name of help file to be printed.
4214 @param[in] SectionToGetHelpOn Pointer to the section specifier(s).
4215 @param[in] PrintCommandText If TRUE, prints the command followed by the help content, otherwise prints
4216 the help content only.
4217 @retval EFI_DEVICE_ERROR The help data format was incorrect.
4218 @retval EFI_NOT_FOUND The help data could not be found.
4219 @retval EFI_SUCCESS The operation was successful.
4220**/
4221EFI_STATUS
4222EFIAPI
4223ShellPrintHelp (
4224 IN CONST CHAR16 *CommandToGetHelpOn,
4225 IN CONST CHAR16 *SectionToGetHelpOn,
4226 IN BOOLEAN PrintCommandText
4227 )
4228{
4229 EFI_STATUS Status;
4230 CHAR16 *OutText;
4231
4232 OutText = NULL;
4233
4234 //
4235 // Get the string to print based
4236 //
4237 Status = gEfiShellProtocol->GetHelpText (CommandToGetHelpOn, SectionToGetHelpOn, &OutText);
4238
4239 //
4240 // make sure we got a valid string
4241 //
4242 if (EFI_ERROR(Status)){
4243 return Status;
4244 }
4245 if (OutText == NULL || StrLen(OutText) == 0) {
4246 return EFI_NOT_FOUND;
4247 }
4248
4249 //
4250 // Chop off trailing stuff we dont need
4251 //
4252 while (OutText[StrLen(OutText)-1] == L'\r' || OutText[StrLen(OutText)-1] == L'\n' || OutText[StrLen(OutText)-1] == L' ') {
4253 OutText[StrLen(OutText)-1] = CHAR_NULL;
4254 }
4255
4256 //
4257 // Print this out to the console
4258 //
4259 if (PrintCommandText) {
4260 ShellPrintEx(-1, -1, L"%H%-14s%N- %s\r\n", CommandToGetHelpOn, OutText);
4261 } else {
4262 ShellPrintEx(-1, -1, L"%N%s\r\n", OutText);
4263 }
4264
4265 SHELL_FREE_NON_NULL(OutText);
4266
4267 return EFI_SUCCESS;
4268}
4269
4270/**
jcarseyfb5278e2013-02-20 18:21:14 +00004271 Function to delete a file by name
4272
4273 @param[in] FileName Pointer to file name to delete.
4274
4275 @retval EFI_SUCCESS the file was deleted sucessfully
4276 @retval EFI_WARN_DELETE_FAILURE the handle was closed, but the file was not
4277 deleted
4278 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
4279 @retval EFI_NOT_FOUND The specified file could not be found on the
4280 device or the file system could not be found
4281 on the device.
4282 @retval EFI_NO_MEDIA The device has no medium.
4283 @retval EFI_MEDIA_CHANGED The device has a different medium in it or the
4284 medium is no longer supported.
4285 @retval EFI_DEVICE_ERROR The device reported an error.
4286 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
4287 @retval EFI_WRITE_PROTECTED The file or medium is write protected.
4288 @retval EFI_ACCESS_DENIED The file was opened read only.
4289 @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the
4290 file.
4291 @retval other The file failed to open
4292**/
4293EFI_STATUS
4294EFIAPI
4295ShellDeleteFileByName(
4296 IN CONST CHAR16 *FileName
4297 )
4298{
4299 EFI_STATUS Status;
4300 SHELL_FILE_HANDLE FileHandle;
4301
4302 Status = ShellFileExists(FileName);
4303
4304 if (Status == EFI_SUCCESS){
4305 Status = ShellOpenFileByName(FileName, &FileHandle, EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE, 0x0);
4306 if (Status == EFI_SUCCESS){
4307 Status = ShellDeleteFile(&FileHandle);
4308 }
4309 }
4310
4311 return(Status);
4312
4313}
Qiu Shumin0960ba12014-09-17 07:58:31 +00004314
4315/**
4316 Cleans off all the quotes in the string.
4317
4318 @param[in] OriginalString pointer to the string to be cleaned.
4319 @param[out] CleanString The new string with all quotes removed.
4320 Memory allocated in the function and free
4321 by caller.
4322
4323 @retval EFI_SUCCESS The operation was successful.
4324**/
4325EFI_STATUS
4326EFIAPI
4327InternalShellStripQuotes (
4328 IN CONST CHAR16 *OriginalString,
4329 OUT CHAR16 **CleanString
4330 )
4331{
4332 CHAR16 *Walker;
4333
4334 if (OriginalString == NULL || CleanString == NULL) {
4335 return EFI_INVALID_PARAMETER;
4336 }
4337
4338 *CleanString = AllocateCopyPool (StrSize (OriginalString), OriginalString);
4339 if (*CleanString == NULL) {
4340 return EFI_OUT_OF_RESOURCES;
4341 }
4342
4343 for (Walker = *CleanString; Walker != NULL && *Walker != CHAR_NULL ; Walker++) {
4344 if (*Walker == L'\"') {
4345 CopyMem(Walker, Walker+1, StrSize(Walker) - sizeof(Walker[0]));
4346 }
4347 }
4348
4349 return EFI_SUCCESS;
4350}
4351