]> git.proxmox.com Git - mirror_edk2.git/blame - ShellPkg/Application/Shell/Shell.c
adding new commands (libraries) to the build.
[mirror_edk2.git] / ShellPkg / Application / Shell / Shell.c
CommitLineData
a405b86d 1/** @file\r
2 This is THE shell (application)\r
3\r
4 Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>\r
5 This program and the accompanying materials\r
6 are licensed and made available under the terms and conditions of the BSD License\r
7 which accompanies this distribution. The full text of the license may be found at\r
8 http://opensource.org/licenses/bsd-license.php\r
9\r
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
13**/\r
14\r
15#include "Shell.h"\r
16\r
17//\r
18// Initialize the global structure\r
19//\r
20SHELL_INFO ShellInfoObject = {\r
21 NULL,\r
22 NULL,\r
23 FALSE,\r
24 FALSE,\r
25 {\r
26 0,\r
27 0,\r
28 0,\r
29 0,\r
30 0,\r
31 0,\r
32 0,\r
33 0,\r
34 0,\r
35 0,\r
36 NULL,\r
37 NULL\r
38 },\r
39 {0,0},\r
40 {\r
41 {0,0},\r
42 0,\r
43 0,\r
44 TRUE\r
45 },\r
46 NULL,\r
47 0,\r
48 NULL,\r
49 NULL,\r
50 NULL,\r
51 NULL,\r
52 NULL,\r
53 {0,0,NULL,NULL},\r
54 {0,0},\r
55};\r
56\r
57STATIC CONST CHAR16 mScriptExtension[] = L".NSH";\r
58STATIC CONST CHAR16 mExecutableExtensions[] = L".NSH;.EFI";\r
3c865f20 59STATIC CONST CHAR16 mStartupScript[] = L"startup.nsh";\r
a405b86d 60\r
61/**\r
62 The entry point for the application.\r
63\r
64 @param[in] ImageHandle The firmware allocated handle for the EFI image.\r
65 @param[in] SystemTable A pointer to the EFI System Table.\r
66\r
67 @retval EFI_SUCCESS The entry point is executed successfully.\r
68 @retval other Some error occurs when executing this entry point.\r
69\r
70**/\r
71EFI_STATUS\r
72EFIAPI\r
73UefiMain (\r
74 IN EFI_HANDLE ImageHandle,\r
75 IN EFI_SYSTEM_TABLE *SystemTable\r
76 )\r
77{\r
78 EFI_STATUS Status;\r
79 CHAR16 *TempString;\r
80 UINTN Size;\r
81// EFI_INPUT_KEY Key;\r
82\r
83// gST->ConOut->OutputString(gST->ConOut, L"ReadKeyStroke Calling\r\n");\r
84//\r
85// Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
86//\r
87// gST->ConOut->OutputString(gST->ConOut, L"ReadKeyStroke Done\r\n");\r
88// gBS->Stall (1000000);\r
89\r
90 if (PcdGet8(PcdShellSupportLevel) > 3) {\r
91 return (EFI_UNSUPPORTED);\r
92 }\r
93\r
94 //\r
95 // Clear the screen\r
96 //\r
97 Status = gST->ConOut->ClearScreen(gST->ConOut);\r
3c865f20 98 if (EFI_ERROR(Status)) {\r
99 return (Status);\r
100 }\r
a405b86d 101\r
102 //\r
103 // Populate the global structure from PCDs\r
104 //\r
105 ShellInfoObject.ImageDevPath = NULL;\r
106 ShellInfoObject.FileDevPath = NULL;\r
107 ShellInfoObject.PageBreakEnabled = PcdGetBool(PcdShellPageBreakDefault);\r
108 ShellInfoObject.ViewingSettings.InsertMode = PcdGetBool(PcdShellInsertModeDefault);\r
109 ShellInfoObject.LogScreenCount = PcdGet8 (PcdShellScreenLogCount );\r
110\r
111 //\r
112 // verify we dont allow for spec violation\r
113 //\r
114 ASSERT(ShellInfoObject.LogScreenCount >= 3);\r
115\r
116 //\r
117 // Initialize the LIST ENTRY objects...\r
118 //\r
119 InitializeListHead(&ShellInfoObject.BufferToFreeList.Link);\r
120 InitializeListHead(&ShellInfoObject.ViewingSettings.CommandHistory.Link);\r
121 InitializeListHead(&ShellInfoObject.SplitList.Link);\r
122\r
123 //\r
124 // Check PCDs for optional features that are not implemented yet.\r
125 //\r
126 if ( PcdGetBool(PcdShellSupportOldProtocols)\r
127 || !FeaturePcdGet(PcdShellRequireHiiPlatform)\r
128 || FeaturePcdGet(PcdShellSupportFrameworkHii)\r
129 ) {\r
130 return (EFI_UNSUPPORTED);\r
131 }\r
132\r
133 //\r
134 // turn off the watchdog timer\r
135 //\r
136 gBS->SetWatchdogTimer (0, 0, 0, NULL);\r
137\r
138 //\r
139 // install our console logger. This will keep a log of the output for back-browsing\r
140 //\r
141 Status = ConsoleLoggerInstall(ShellInfoObject.LogScreenCount, &ShellInfoObject.ConsoleInfo);\r
3c865f20 142 if (!EFI_ERROR(Status)) {\r
143 //\r
144 // Enable the cursor to be visible\r
145 //\r
146 gST->ConOut->EnableCursor (gST->ConOut, TRUE);\r
a405b86d 147\r
3c865f20 148 //\r
149 // If supporting EFI 1.1 we need to install HII protocol\r
150 // only do this if PcdShellRequireHiiPlatform == FALSE\r
151 //\r
152 // remove EFI_UNSUPPORTED check above when complete.\r
153 ///@todo add support for Framework HII\r
a405b86d 154\r
3c865f20 155 //\r
156 // install our (solitary) HII package\r
157 //\r
158 ShellInfoObject.HiiHandle = HiiAddPackages (&gEfiCallerIdGuid, gImageHandle, ShellStrings, NULL);\r
a405b86d 159 if (ShellInfoObject.HiiHandle == NULL) {\r
3c865f20 160 if (PcdGetBool(PcdShellSupportFrameworkHii)) {\r
161 ///@todo Add our package into Framework HII\r
162 }\r
163 if (ShellInfoObject.HiiHandle == NULL) {\r
164 return (EFI_NOT_STARTED);\r
165 }\r
a405b86d 166 }\r
a405b86d 167\r
3c865f20 168 //\r
169 // create and install the EfiShellParametersProtocol\r
170 //\r
171 Status = CreatePopulateInstallShellParametersProtocol(&ShellInfoObject.NewShellParametersProtocol, &ShellInfoObject.RootShellInstance);\r
172 ASSERT_EFI_ERROR(Status);\r
173 ASSERT(ShellInfoObject.NewShellParametersProtocol != NULL);\r
a405b86d 174\r
3c865f20 175 //\r
176 // create and install the EfiShellProtocol\r
177 //\r
178 Status = CreatePopulateInstallShellProtocol(&ShellInfoObject.NewEfiShellProtocol);\r
179 ASSERT_EFI_ERROR(Status);\r
180 ASSERT(ShellInfoObject.NewEfiShellProtocol != NULL);\r
a405b86d 181\r
3c865f20 182 //\r
183 // Now initialize the shell library (it requires Shell Parameters protocol)\r
184 //\r
185 Status = ShellInitialize();\r
186 ASSERT_EFI_ERROR(Status);\r
a405b86d 187\r
3c865f20 188 Status = CommandInit();\r
189 ASSERT_EFI_ERROR(Status);\r
a405b86d 190\r
3c865f20 191 //\r
192 // Check the command line\r
193 //\r
194 Status = ProcessCommandLine();\r
a405b86d 195\r
3c865f20 196 //\r
197 // If shell support level is >= 1 create the mappings and paths\r
198 //\r
199 if (PcdGet8(PcdShellSupportLevel) >= 1) {\r
200 Status = ShellCommandCreateInitialMappingsAndPaths();\r
201 }\r
a405b86d 202\r
3c865f20 203 //\r
204 // save the device path for the loaded image and the device path for the filepath (under loaded image)\r
205 // These are where to look for the startup.nsh file\r
206 //\r
207 Status = GetDevicePathsForImageAndFile(&ShellInfoObject.ImageDevPath, &ShellInfoObject.FileDevPath);\r
a405b86d 208 ASSERT_EFI_ERROR(Status);\r
a405b86d 209\r
3c865f20 210 //\r
211 // Display the version\r
212 //\r
213 if (!ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoVersion) {\r
214 ShellPrintHiiEx (\r
215 0,\r
216 gST->ConOut->Mode->CursorRow,\r
217 NULL,\r
218 STRING_TOKEN (STR_VER_OUTPUT_MAIN),\r
219 ShellInfoObject.HiiHandle,\r
220 SupportLevel[PcdGet8(PcdShellSupportLevel)],\r
221 gEfiShellProtocol->MajorVersion,\r
222 gEfiShellProtocol->MinorVersion,\r
223 (gST->Hdr.Revision&0xffff0000)>>16,\r
224 (gST->Hdr.Revision&0x0000ffff),\r
225 gST->FirmwareVendor,\r
226 gST->FirmwareRevision\r
227 );\r
228 }\r
a405b86d 229\r
3c865f20 230 //\r
231 // Display the mapping\r
232 //\r
233 if (PcdGet8(PcdShellSupportLevel) >= 2 && !ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoMap) {\r
234 Status = RunCommand(L"map");\r
235 ASSERT_EFI_ERROR(Status);\r
236 }\r
a405b86d 237\r
3c865f20 238 //\r
239 // init all the built in alias'\r
240 //\r
241 Status = SetBuiltInAlias();\r
242 ASSERT_EFI_ERROR(Status);\r
a405b86d 243\r
3c865f20 244 //\r
245 // Initialize environment variables\r
246 //\r
247 if (ShellCommandGetProfileList() != NULL) {\r
248 Status = InternalEfiShellSetEnv(L"profiles", ShellCommandGetProfileList(), TRUE);\r
249 ASSERT_EFI_ERROR(Status);\r
250 }\r
a405b86d 251\r
3c865f20 252 Size = 100;\r
253 TempString = AllocateZeroPool(Size);\r
a405b86d 254\r
3c865f20 255 UnicodeSPrint(TempString, Size, L"%d", PcdGet8(PcdShellSupportLevel));\r
256 Status = InternalEfiShellSetEnv(L"uefishellsupport", TempString, TRUE);\r
257 ASSERT_EFI_ERROR(Status);\r
a405b86d 258\r
3c865f20 259 UnicodeSPrint(TempString, Size, L"%d.%d", ShellInfoObject.NewEfiShellProtocol->MajorVersion, ShellInfoObject.NewEfiShellProtocol->MinorVersion);\r
260 Status = InternalEfiShellSetEnv(L"uefishellversion", TempString, TRUE);\r
261 ASSERT_EFI_ERROR(Status);\r
a405b86d 262\r
3c865f20 263 UnicodeSPrint(TempString, Size, L"%d.%d", (gST->Hdr.Revision & 0xFFFF0000) >> 16, gST->Hdr.Revision & 0x0000FFFF);\r
264 Status = InternalEfiShellSetEnv(L"uefiversion", TempString, TRUE);\r
265 ASSERT_EFI_ERROR(Status);\r
a405b86d 266\r
3c865f20 267 FreePool(TempString);\r
a405b86d 268\r
3c865f20 269 if (!EFI_ERROR(Status)) {\r
270 if (!ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoInterrupt) {\r
a405b86d 271 //\r
3c865f20 272 // Set up the event for CTRL-C monitoring...\r
a405b86d 273 //\r
a405b86d 274\r
3c865f20 275 ///@todo add support for using SimpleInputEx here\r
276 // if SimpleInputEx is not available display a warning.\r
277 }\r
278\r
279 if (!EFI_ERROR(Status) && PcdGet8(PcdShellSupportLevel) >= 1) {\r
a405b86d 280 //\r
3c865f20 281 // process the startup script or launch the called app.\r
a405b86d 282 //\r
3c865f20 283 Status = DoStartupScript(ShellInfoObject.ImageDevPath, ShellInfoObject.FileDevPath);\r
284 }\r
a405b86d 285\r
3c865f20 286 if ((PcdGet8(PcdShellSupportLevel) >= 3 || PcdGetBool(PcdShellForceConsole)) && !EFI_ERROR(Status) && !ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoConsoleIn) {\r
a405b86d 287 //\r
3c865f20 288 // begin the UI waiting loop\r
a405b86d 289 //\r
3c865f20 290 do {\r
291 //\r
292 // clean out all the memory allocated for CONST <something> * return values\r
293 // between each shell prompt presentation\r
294 //\r
295 if (!IsListEmpty(&ShellInfoObject.BufferToFreeList.Link)){\r
296 FreeBufferList(&ShellInfoObject.BufferToFreeList);\r
297 }\r
298\r
299 //\r
300 // Reset page break back to default.\r
301 //\r
302 ShellInfoObject.PageBreakEnabled = PcdGetBool(PcdShellPageBreakDefault);\r
303 ShellInfoObject.ConsoleInfo->Enabled = TRUE;\r
304 ShellInfoObject.ConsoleInfo->RowCounter = 0;\r
305\r
306 //\r
307 // Display Prompt\r
308 //\r
309 Status = DoShellPrompt();\r
310 } while (!ShellCommandGetExit());\r
311 }\r
a405b86d 312 }\r
313 }\r
3c865f20 314\r
a405b86d 315 //\r
316 // uninstall protocols / free memory / etc...\r
317 //\r
318 if (ShellInfoObject.UserBreakTimer != NULL) {\r
319 gBS->CloseEvent(ShellInfoObject.UserBreakTimer);\r
320 DEBUG_CODE(ShellInfoObject.UserBreakTimer = NULL;);\r
321 }\r
322\r
323 if (ShellInfoObject.NewEfiShellProtocol->IsRootShell()){\r
324 ShellInfoObject.NewEfiShellProtocol->SetEnv(L"cwd", L"", TRUE);\r
325 }\r
326\r
327 if (ShellInfoObject.ImageDevPath != NULL) {\r
328 FreePool(ShellInfoObject.ImageDevPath);\r
329 DEBUG_CODE(ShellInfoObject.ImageDevPath = NULL;);\r
330 }\r
331 if (ShellInfoObject.FileDevPath != NULL) {\r
332 FreePool(ShellInfoObject.FileDevPath);\r
333 DEBUG_CODE(ShellInfoObject.FileDevPath = NULL;);\r
334 }\r
335 if (ShellInfoObject.NewShellParametersProtocol != NULL) {\r
336 CleanUpShellParametersProtocol(ShellInfoObject.NewShellParametersProtocol);\r
337 DEBUG_CODE(ShellInfoObject.NewShellParametersProtocol = NULL;);\r
338 }\r
339 if (ShellInfoObject.NewEfiShellProtocol != NULL){\r
340 CleanUpShellProtocol(ShellInfoObject.NewEfiShellProtocol);\r
341 DEBUG_CODE(ShellInfoObject.NewEfiShellProtocol = NULL;);\r
342 }\r
343\r
344 if (!IsListEmpty(&ShellInfoObject.BufferToFreeList.Link)){\r
345 FreeBufferList(&ShellInfoObject.BufferToFreeList);\r
346 }\r
347\r
348 if (!IsListEmpty(&ShellInfoObject.SplitList.Link)){\r
3c865f20 349 ASSERT(FALSE); ///@todo finish this de-allocation.\r
a405b86d 350 }\r
351\r
352 if (ShellInfoObject.ShellInitSettings.FileName != NULL) {\r
353 FreePool(ShellInfoObject.ShellInitSettings.FileName);\r
354 DEBUG_CODE(ShellInfoObject.ShellInitSettings.FileName = NULL;);\r
355 }\r
356\r
357 if (ShellInfoObject.ShellInitSettings.FileOptions != NULL) {\r
358 FreePool(ShellInfoObject.ShellInitSettings.FileOptions);\r
359 DEBUG_CODE(ShellInfoObject.ShellInitSettings.FileOptions = NULL;);\r
360 }\r
361\r
362 if (ShellInfoObject.HiiHandle != NULL) {\r
363 HiiRemovePackages(ShellInfoObject.HiiHandle);\r
364 DEBUG_CODE(ShellInfoObject.HiiHandle = NULL;);\r
365 }\r
366\r
367 if (!IsListEmpty(&ShellInfoObject.ViewingSettings.CommandHistory.Link)){\r
368 FreeBufferList(&ShellInfoObject.ViewingSettings.CommandHistory);\r
369 }\r
370\r
371 ASSERT(ShellInfoObject.ConsoleInfo != NULL);\r
372 if (ShellInfoObject.ConsoleInfo != NULL) {\r
373 ConsoleLoggerUninstall(ShellInfoObject.ConsoleInfo);\r
374 FreePool(ShellInfoObject.ConsoleInfo);\r
375 DEBUG_CODE(ShellInfoObject.ConsoleInfo = NULL;);\r
376 }\r
377\r
378 return (Status);\r
379}\r
380\r
381/**\r
382 Sets all the alias' that were registered with the ShellCommandLib library.\r
383\r
384 @retval EFI_SUCCESS all init commands were run sucessfully.\r
385**/\r
386EFI_STATUS\r
387EFIAPI\r
388SetBuiltInAlias(\r
389 )\r
390{\r
391 EFI_STATUS Status;\r
392 CONST ALIAS_LIST *List;\r
393 ALIAS_LIST *Node;\r
394\r
395 //\r
396 // Get all the commands we want to run\r
397 //\r
398 List = ShellCommandGetInitAliasList();\r
399\r
400 //\r
401 // for each command in the List\r
402 //\r
403 for ( Node = (ALIAS_LIST*)GetFirstNode(&List->Link)\r
404 ; !IsNull (&List->Link, &Node->Link)\r
405 ; Node = (ALIAS_LIST *)GetNextNode(&List->Link, &Node->Link)\r
406 ){\r
407 //\r
408 // install the alias'\r
409 //\r
410 Status = InternalSetAlias(Node->CommandString, Node->Alias, TRUE);\r
411 ASSERT_EFI_ERROR(Status);\r
412 }\r
413 return (EFI_SUCCESS);\r
414}\r
415\r
416/**\r
417 Internal function to determine if 2 command names are really the same.\r
418\r
419 @param[in] Command1 The pointer to the first command name.\r
420 @param[in] Command2 The pointer to the second command name.\r
421\r
422 @retval TRUE The 2 command names are the same.\r
423 @retval FALSE The 2 command names are not the same.\r
424**/\r
425BOOLEAN\r
426EFIAPI\r
427IsCommand(\r
428 IN CONST CHAR16 *Command1,\r
429 IN CONST CHAR16 *Command2\r
430 )\r
431{\r
432 if (StringNoCaseCompare(&Command1, &Command2) == 0) {\r
433 return (TRUE);\r
434 }\r
435 return (FALSE);\r
436}\r
437\r
438/**\r
439 Internal function to determine if a command is a script only command.\r
440\r
441 @param[in] CommandName The pointer to the command name.\r
442\r
443 @retval TRUE The command is a script only command.\r
444 @retval FALSE The command is not a script only command.\r
445**/\r
446BOOLEAN\r
447EFIAPI\r
448IsScriptOnlyCommand(\r
449 IN CONST CHAR16 *CommandName\r
450 )\r
451{\r
452 if (IsCommand(CommandName, L"for")\r
453 ||IsCommand(CommandName, L"endfor")\r
454 ||IsCommand(CommandName, L"if")\r
455 ||IsCommand(CommandName, L"else")\r
456 ||IsCommand(CommandName, L"endif")\r
457 ||IsCommand(CommandName, L"goto")) {\r
458 return (TRUE);\r
459 }\r
460 return (FALSE);\r
461}\r
462\r
463\r
464\r
465/**\r
466 This function will populate the 2 device path protocol parameters based on the\r
467 global gImageHandle. The DevPath will point to the device path for the handle that has\r
468 loaded image protocol installed on it. The FilePath will point to the device path\r
469 for the file that was loaded.\r
470\r
471 @param[in,out] DevPath On a sucessful return the device path to the loaded image.\r
472 @param[in,out] FilePath On a sucessful return the device path to the file.\r
473\r
474 @retval EFI_SUCCESS The 2 device paths were sucessfully returned.\r
475 @retval other A error from gBS->HandleProtocol.\r
476\r
477 @sa HandleProtocol\r
478**/\r
479EFI_STATUS\r
480EFIAPI\r
481GetDevicePathsForImageAndFile (\r
482 IN OUT EFI_DEVICE_PATH_PROTOCOL **DevPath,\r
483 IN OUT EFI_DEVICE_PATH_PROTOCOL **FilePath\r
484 )\r
485{\r
486 EFI_STATUS Status;\r
487 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;\r
488 EFI_DEVICE_PATH_PROTOCOL *ImageDevicePath;\r
489\r
490 ASSERT(DevPath != NULL);\r
491 ASSERT(FilePath != NULL);\r
492\r
493 Status = gBS->OpenProtocol (\r
494 gImageHandle,\r
495 &gEfiLoadedImageProtocolGuid,\r
496 (VOID**)&LoadedImage,\r
497 gImageHandle,\r
498 NULL,\r
499 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
500 );\r
501 if (!EFI_ERROR (Status)) {\r
502 Status = gBS->OpenProtocol (\r
503 LoadedImage->DeviceHandle,\r
504 &gEfiDevicePathProtocolGuid,\r
505 (VOID**)&ImageDevicePath,\r
506 gImageHandle,\r
507 NULL,\r
508 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
509 );\r
510 if (!EFI_ERROR (Status)) {\r
511 *DevPath = DuplicateDevicePath (ImageDevicePath);\r
512 *FilePath = DuplicateDevicePath (LoadedImage->FilePath);\r
513 }\r
514 gBS->CloseProtocol(\r
515 gImageHandle,\r
516 &gEfiLoadedImageProtocolGuid,\r
517 gImageHandle,\r
518 NULL);\r
519 }\r
520 return (Status);\r
521}\r
522\r
523STATIC CONST SHELL_PARAM_ITEM mShellParamList[] = {\r
524 {L"-nostartup", TypeFlag},\r
525 {L"-startup", TypeFlag},\r
526 {L"-noconsoleout", TypeFlag},\r
527 {L"-noconsolein", TypeFlag},\r
528 {L"-nointerrupt", TypeFlag},\r
529 {L"-nomap", TypeFlag},\r
530 {L"-noversion", TypeFlag},\r
531 {L"-startup", TypeFlag},\r
532 {L"-delay", TypeValue},\r
533 {NULL, TypeMax}\r
534 };\r
535/**\r
536 Process all Uefi Shell 2.0 command line options.\r
537\r
538 see Uefi Shell 2.0 section 3.2 for full details.\r
539\r
540 the command line must resemble the following:\r
541\r
542 shell.efi [ShellOpt-options] [options] [file-name [file-name-options]]\r
543\r
544 ShellOpt-options Options which control the initialization behavior of the shell.\r
545 These options are read from the EFI global variable "ShellOpt"\r
546 and are processed before options or file-name.\r
547\r
548 options Options which control the initialization behavior of the shell.\r
549\r
550 file-name The name of a UEFI shell application or script to be executed\r
551 after initialization is complete. By default, if file-name is\r
552 specified, then -nostartup is implied. Scripts are not supported\r
553 by level 0.\r
554\r
555 file-name-options The command-line options that are passed to file-name when it\r
556 is invoked.\r
557\r
558 This will initialize the ShellInfoObject.ShellInitSettings global variable.\r
559\r
560 @retval EFI_SUCCESS The variable is initialized.\r
561**/\r
562EFI_STATUS\r
563EFIAPI\r
564ProcessCommandLine(\r
565 VOID\r
566 )\r
567{\r
568 EFI_STATUS Status;\r
569 LIST_ENTRY *Package;\r
570 UINTN Size;\r
571 CONST CHAR16 *TempConst;\r
572 UINTN Count;\r
573 UINTN LoopVar;\r
574 CHAR16 *ProblemParam;\r
575\r
576 Package = NULL;\r
577 ProblemParam = NULL;\r
578 \r
579 Status = ShellCommandLineParse (mShellParamList, &Package, NULL, FALSE);\r
580\r
581 Count = 1;\r
582 Size = 0;\r
583 TempConst = ShellCommandLineGetRawValue(Package, Count++);\r
584 if (TempConst != NULL && StrLen(TempConst)) {\r
585 ShellInfoObject.ShellInitSettings.FileName = AllocatePool(StrSize(TempConst));\r
3c865f20 586 if (ShellInfoObject.ShellInitSettings.FileName == NULL) {\r
587 return (EFI_OUT_OF_RESOURCES);\r
588 }\r
a405b86d 589 StrCpy(ShellInfoObject.ShellInitSettings.FileName, TempConst);\r
590 ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoStartup = 1;\r
591 for (LoopVar = 0 ; LoopVar < gEfiShellParametersProtocol->Argc ; LoopVar++) {\r
592 if (StrCmp(gEfiShellParametersProtocol->Argv[LoopVar], ShellInfoObject.ShellInitSettings.FileName)==0) {\r
593 LoopVar++;\r
594 //\r
595 // We found the file... add the rest of the params...\r
596 //\r
597 for ( ; LoopVar < gEfiShellParametersProtocol->Argc ; LoopVar++) {\r
598 ASSERT((ShellInfoObject.ShellInitSettings.FileOptions == NULL && Size == 0) || (ShellInfoObject.ShellInitSettings.FileOptions != NULL));\r
599 StrnCatGrow(&ShellInfoObject.ShellInitSettings.FileOptions,\r
600 &Size,\r
601 L" ",\r
602 0);\r
3c865f20 603 if (ShellInfoObject.ShellInitSettings.FileOptions == NULL) {\r
604 SHELL_FREE_NON_NULL(ShellInfoObject.ShellInitSettings.FileName);\r
605 return (EFI_OUT_OF_RESOURCES);\r
606 }\r
a405b86d 607 StrnCatGrow(&ShellInfoObject.ShellInitSettings.FileOptions,\r
608 &Size,\r
609 gEfiShellParametersProtocol->Argv[LoopVar],\r
610 0);\r
3c865f20 611 if (ShellInfoObject.ShellInitSettings.FileOptions == NULL) {\r
612 SHELL_FREE_NON_NULL(ShellInfoObject.ShellInitSettings.FileName);\r
613 return (EFI_OUT_OF_RESOURCES);\r
614 }\r
a405b86d 615 }\r
616 }\r
617 }\r
618 } else {\r
619 ShellCommandLineFreeVarList(Package);\r
620 Package = NULL;\r
621 Status = ShellCommandLineParse (mShellParamList, &Package, &ProblemParam, FALSE);\r
622 if (EFI_ERROR(Status)) {\r
623 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), ShellInfoObject.HiiHandle, ProblemParam);\r
624 FreePool(ProblemParam);\r
625 ShellCommandLineFreeVarList(Package);\r
626 return (EFI_INVALID_PARAMETER);\r
627 }\r
628 }\r
629\r
630 ShellInfoObject.ShellInitSettings.BitUnion.Bits.Startup = ShellCommandLineGetFlag(Package, L"-startup");\r
631 ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoStartup = ShellCommandLineGetFlag(Package, L"-nostartup");\r
632 ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoConsoleOut = ShellCommandLineGetFlag(Package, L"-noconsoleout");\r
633 ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoConsoleIn = ShellCommandLineGetFlag(Package, L"-noconsolein");\r
634 ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoInterrupt = ShellCommandLineGetFlag(Package, L"-nointerrupt");\r
635 ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoMap = ShellCommandLineGetFlag(Package, L"-nomap");\r
636 ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoVersion = ShellCommandLineGetFlag(Package, L"-noversion");\r
637 ShellInfoObject.ShellInitSettings.BitUnion.Bits.Delay = ShellCommandLineGetFlag(Package, L"-delay");\r
638\r
639 if (ShellInfoObject.ShellInitSettings.BitUnion.Bits.Delay) {\r
640 TempConst = ShellCommandLineGetValue(Package, L"-delay");\r
641 if (TempConst != NULL) {\r
642 ShellInfoObject.ShellInitSettings.Delay = StrDecimalToUintn (TempConst);\r
643 } else {\r
644 ShellInfoObject.ShellInitSettings.Delay = 5;\r
645 }\r
646 } else {\r
647 ShellInfoObject.ShellInitSettings.Delay = 5;\r
648 }\r
649\r
650 ShellCommandLineFreeVarList(Package);\r
651\r
652 return (Status);\r
653}\r
654\r
655/**\r
656 Handles all interaction with the default startup script.\r
657\r
658 this will check that the correct command line parameters were passed, handle the delay, and then start running the script.\r
659\r
660 @param ImagePath the path to the image for shell. first place to look for the startup script\r
661 @param FilePath the path to the file for shell. second place to look for the startup script.\r
662\r
663 @retval EFI_SUCCESS the variable is initialized.\r
664**/\r
665EFI_STATUS\r
666EFIAPI\r
667DoStartupScript(\r
668 EFI_DEVICE_PATH_PROTOCOL *ImagePath,\r
669 EFI_DEVICE_PATH_PROTOCOL *FilePath\r
670 )\r
671{\r
672 EFI_STATUS Status;\r
673 UINTN Delay;\r
674 EFI_INPUT_KEY Key;\r
675 SHELL_FILE_HANDLE FileHandle;\r
676 EFI_DEVICE_PATH_PROTOCOL *NewPath;\r
677 EFI_DEVICE_PATH_PROTOCOL *NamePath;\r
678 CHAR16 *FileStringPath;\r
679 UINTN NewSize;\r
680\r
681 Key.UnicodeChar = CHAR_NULL;\r
682 Key.ScanCode = 0;\r
683 FileHandle = NULL;\r
684\r
685 if (!ShellInfoObject.ShellInitSettings.BitUnion.Bits.Startup && ShellInfoObject.ShellInitSettings.FileName != NULL) {\r
686 //\r
687 // launch something else instead\r
688 //\r
689 NewSize = StrSize(ShellInfoObject.ShellInitSettings.FileName);\r
690 if (ShellInfoObject.ShellInitSettings.FileOptions != NULL) {\r
691 NewSize += StrSize(ShellInfoObject.ShellInitSettings.FileOptions) + sizeof(CHAR16);\r
692 }\r
693 FileStringPath = AllocateZeroPool(NewSize);\r
3c865f20 694 if (FileStringPath == NULL) {\r
695 return (EFI_OUT_OF_RESOURCES);\r
696 }\r
a405b86d 697 StrCpy(FileStringPath, ShellInfoObject.ShellInitSettings.FileName);\r
698 if (ShellInfoObject.ShellInitSettings.FileOptions != NULL) {\r
3c865f20 699 StrCat(FileStringPath, L" ");\r
a405b86d 700 StrCat(FileStringPath, ShellInfoObject.ShellInitSettings.FileOptions);\r
701 }\r
702 Status = RunCommand(FileStringPath);\r
703 FreePool(FileStringPath);\r
704 return (Status);\r
705\r
706 }\r
707\r
708 //\r
709 // for shell level 0 we do no scripts\r
710 // Without the Startup bit overriding we allow for nostartup to prevent scripts\r
711 //\r
712 if ( (PcdGet8(PcdShellSupportLevel) < 1)\r
713 || (ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoStartup && !ShellInfoObject.ShellInitSettings.BitUnion.Bits.Startup)\r
714 ){\r
715 return (EFI_SUCCESS);\r
716 }\r
717\r
718 //\r
719 // print out our warning and see if they press a key\r
720 //\r
721 for ( Status = EFI_UNSUPPORTED, Delay = (ShellInfoObject.ShellInitSettings.Delay * 10)\r
722 ; Delay > 0 && EFI_ERROR(Status)\r
723 ; Delay--\r
724 ){\r
725 ShellPrintHiiEx(0, gST->ConOut->Mode->CursorRow, NULL, STRING_TOKEN (STR_SHELL_STARTUP_QUESTION), ShellInfoObject.HiiHandle, Delay/10);\r
726 gBS->Stall (100000);\r
727 Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
728 }\r
729 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_CRLF), ShellInfoObject.HiiHandle);\r
730\r
731 //\r
732 // ESC was pressed\r
733 //\r
734 if (Status == EFI_SUCCESS && Key.UnicodeChar == 0 && Key.ScanCode == SCAN_ESC) {\r
735 return (EFI_SUCCESS);\r
736 }\r
737\r
3c865f20 738 NamePath = FileDevicePath (NULL, mStartupScript);\r
a405b86d 739 //\r
740 // Try the first location\r
741 //\r
742 NewPath = AppendDevicePathNode (ImagePath, NamePath);\r
743 Status = InternalOpenFileDevicePath(NewPath, &FileHandle, EFI_FILE_MODE_READ, 0);\r
744 if (EFI_ERROR(Status)) {\r
745 //\r
746 // Try the second location\r
747 //\r
748 FreePool(NewPath);\r
749 NewPath = AppendDevicePathNode (FilePath , NamePath);\r
750 Status = InternalOpenFileDevicePath(NewPath, &FileHandle, EFI_FILE_MODE_READ, 0);\r
751 }\r
752\r
753 //\r
754 // If we got a file, run it\r
755 //\r
756 if (!EFI_ERROR(Status)) {\r
3c865f20 757 Status = RunScriptFileHandle (FileHandle, mStartupScript);\r
a405b86d 758 ShellInfoObject.NewEfiShellProtocol->CloseFile(FileHandle);\r
759 } else {\r
3c865f20 760 FileStringPath = ShellFindFilePath(mStartupScript);\r
761 if (FileStringPath == NULL) {\r
762 //\r
763 // we return success since we dont need to have a startup script\r
764 //\r
765 Status = EFI_SUCCESS;\r
766 ASSERT(FileHandle == NULL);\r
767 } else {\r
768 Status = RunScriptFile(FileStringPath);\r
769 FreePool(FileStringPath);\r
770 }\r
a405b86d 771 }\r
772\r
773 FreePool(NamePath);\r
774 FreePool(NewPath);\r
775\r
776 return (Status);\r
777}\r
778\r
779/**\r
780 Function to perform the shell prompt looping. It will do a single prompt,\r
781 dispatch the result, and then return. It is expected that the caller will\r
782 call this function in a loop many times.\r
783\r
784 @retval EFI_SUCCESS\r
785 @retval RETURN_ABORTED\r
786**/\r
787EFI_STATUS\r
788EFIAPI\r
789DoShellPrompt (\r
790 VOID\r
791 )\r
792{\r
793 UINTN Column;\r
794 UINTN Row;\r
795 CHAR16 *CmdLine;\r
796 CONST CHAR16 *CurDir;\r
797 UINTN BufferSize;\r
798 EFI_STATUS Status;\r
799\r
800 CurDir = NULL;\r
801\r
802 //\r
803 // Get screen setting to decide size of the command line buffer\r
804 //\r
805 gST->ConOut->QueryMode (gST->ConOut, gST->ConOut->Mode->Mode, &Column, &Row);\r
806 BufferSize = Column * Row * sizeof (CHAR16);\r
807 CmdLine = AllocateZeroPool (BufferSize);\r
808 if (CmdLine == NULL) {\r
809 return EFI_OUT_OF_RESOURCES;\r
810 }\r
811\r
812 CurDir = ShellInfoObject.NewEfiShellProtocol->GetEnv(L"cwd");\r
813\r
814 //\r
815 // Prompt for input\r
816 //\r
817 gST->ConOut->SetCursorPosition (gST->ConOut, 0, gST->ConOut->Mode->CursorRow);\r
818\r
819 if (CurDir != NULL && StrLen(CurDir) > 1) {\r
820 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_CURDIR), ShellInfoObject.HiiHandle, CurDir);\r
821 } else {\r
822 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_SHELL), ShellInfoObject.HiiHandle);\r
823 }\r
824\r
825 //\r
826 // Read a line from the console\r
827 //\r
828 Status = ShellInfoObject.NewEfiShellProtocol->ReadFile(ShellInfoObject.NewShellParametersProtocol->StdIn, &BufferSize, CmdLine);\r
829\r
830 //\r
831 // Null terminate the string and parse it\r
832 //\r
833 if (!EFI_ERROR (Status)) {\r
834 CmdLine[BufferSize / sizeof (CHAR16)] = CHAR_NULL;\r
835 Status = RunCommand(CmdLine);\r
836 }\r
837\r
838 //\r
839 // Done with this command\r
840 //\r
841 FreePool (CmdLine);\r
842 return Status;\r
843}\r
844\r
845/**\r
846 Add a buffer to the Buffer To Free List for safely returning buffers to other\r
847 places without risking letting them modify internal shell information.\r
848\r
849 @param Buffer Something to pass to FreePool when the shell is exiting.\r
850**/\r
851VOID*\r
852EFIAPI\r
853AddBufferToFreeList(\r
854 VOID *Buffer\r
855 )\r
856{\r
857 BUFFER_LIST *BufferListEntry;\r
858\r
859 if (Buffer == NULL) {\r
860 return (NULL);\r
861 }\r
862\r
863 BufferListEntry = AllocateZeroPool(sizeof(BUFFER_LIST));\r
864 ASSERT(BufferListEntry != NULL);\r
865 BufferListEntry->Buffer = Buffer;\r
866 InsertTailList(&ShellInfoObject.BufferToFreeList.Link, &BufferListEntry->Link);\r
867 return (Buffer);\r
868}\r
869\r
870/**\r
871 Add a buffer to the Line History List\r
872\r
873 @param Buffer The line buffer to add.\r
874**/\r
875VOID\r
876EFIAPI\r
877AddLineToCommandHistory(\r
878 IN CONST CHAR16 *Buffer\r
879 )\r
880{\r
881 BUFFER_LIST *Node;\r
882\r
883 Node = AllocateZeroPool(sizeof(BUFFER_LIST));\r
884 ASSERT(Node != NULL);\r
885 Node->Buffer = AllocateZeroPool(StrSize(Buffer));\r
886 ASSERT(Node->Buffer != NULL);\r
887 StrCpy(Node->Buffer, Buffer);\r
888\r
889 InsertTailList(&ShellInfoObject.ViewingSettings.CommandHistory.Link, &Node->Link);\r
890}\r
891\r
892/**\r
893 Checks if a string is an alias for another command. If yes, then it replaces the alias name\r
894 with the correct command name.\r
895\r
896 @param[in,out] CommandString Upon entry the potential alias. Upon return the\r
897 command name if it was an alias. If it was not\r
898 an alias it will be unchanged. This function may\r
899 change the buffer to fit the command name.\r
900\r
901 @retval EFI_SUCCESS The name was changed.\r
902 @retval EFI_SUCCESS The name was not an alias.\r
903 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.\r
904**/\r
905EFI_STATUS\r
906EFIAPI\r
907ShellConvertAlias(\r
908 IN OUT CHAR16 **CommandString\r
909 )\r
910{\r
911 CONST CHAR16 *NewString;\r
912\r
913 NewString = ShellInfoObject.NewEfiShellProtocol->GetAlias(*CommandString, NULL);\r
914 if (NewString == NULL) {\r
915 return (EFI_SUCCESS);\r
916 }\r
917 FreePool(*CommandString);\r
918 *CommandString = AllocatePool(StrSize(NewString));\r
919 if (*CommandString == NULL) {\r
920 return (EFI_OUT_OF_RESOURCES);\r
921 }\r
922 StrCpy(*CommandString, NewString);\r
923 return (EFI_SUCCESS);\r
924}\r
925\r
926/**\r
927 Function allocates a new command line and replaces all instances of environment\r
928 variable names that are correctly preset to their values.\r
929\r
930 If the return value is not NULL the memory must be caller freed.\r
931\r
932 @param[in] OriginalCommandLine The original command line\r
933\r
934 @retval NULL An error ocurred.\r
935 @return The new command line with no environment variables present.\r
936**/\r
937CHAR16*\r
938EFIAPI\r
939ShellConvertVariables (\r
940 IN CONST CHAR16 *OriginalCommandLine\r
941 )\r
942{\r
943 CONST CHAR16 *MasterEnvList;\r
944 UINTN NewSize;\r
945 CHAR16 *NewCommandLine1;\r
946 CHAR16 *NewCommandLine2;\r
947 CHAR16 *Temp;\r
948 UINTN ItemSize;\r
949 CHAR16 *ItemTemp;\r
950 SCRIPT_FILE *CurrentScriptFile;\r
951 ALIAS_LIST *AliasListNode;\r
952\r
953 ASSERT(OriginalCommandLine != NULL);\r
954\r
955 ItemSize = 0;\r
956 NewSize = StrSize(OriginalCommandLine);\r
957 CurrentScriptFile = ShellCommandGetCurrentScriptFile();\r
958 Temp = NULL;\r
959\r
960 ///@todo update this to handle the %0 - %9 for scripting only (borrow from line 1256 area) ? ? ?\r
961\r
962 //\r
963 // calculate the size required for the post-conversion string...\r
964 //\r
965 if (CurrentScriptFile != NULL) {\r
966 for (AliasListNode = (ALIAS_LIST*)GetFirstNode(&CurrentScriptFile->SubstList)\r
967 ; !IsNull(&CurrentScriptFile->SubstList, &AliasListNode->Link)\r
968 ; AliasListNode = (ALIAS_LIST*)GetNextNode(&CurrentScriptFile->SubstList, &AliasListNode->Link)\r
969 ){\r
970 for (Temp = StrStr(OriginalCommandLine, AliasListNode->Alias)\r
971 ; Temp != NULL\r
972 ; Temp = StrStr(Temp+1, AliasListNode->Alias)\r
973 ){\r
974 //\r
975 // we need a preceeding and if there is space no ^ preceeding (if no space ignore)\r
976 //\r
977 if ((((Temp-OriginalCommandLine)>2) && *(Temp-2) != L'^') || ((Temp-OriginalCommandLine)<=2)) {\r
978 NewSize += StrSize(AliasListNode->CommandString);\r
979 }\r
980 }\r
981 }\r
982 }\r
983\r
984 for (MasterEnvList = EfiShellGetEnv(NULL)\r
985 ; MasterEnvList != NULL && *MasterEnvList != CHAR_NULL //&& *(MasterEnvList+1) != CHAR_NULL\r
986 ; MasterEnvList += StrLen(MasterEnvList) + 1\r
987 ){\r
988 if (StrSize(MasterEnvList) > ItemSize) {\r
989 ItemSize = StrSize(MasterEnvList);\r
990 }\r
991 for (Temp = StrStr(OriginalCommandLine, MasterEnvList)\r
992 ; Temp != NULL\r
993 ; Temp = StrStr(Temp+1, MasterEnvList)\r
994 ){\r
995 //\r
996 // we need a preceeding and following % and if there is space no ^ preceeding (if no space ignore)\r
997 //\r
998 if (*(Temp-1) == L'%' && *(Temp+StrLen(MasterEnvList)) == L'%' &&\r
999 ((((Temp-OriginalCommandLine)>2) && *(Temp-2) != L'^') || ((Temp-OriginalCommandLine)<=2))) {\r
1000 NewSize+=StrSize(EfiShellGetEnv(MasterEnvList));\r
1001 }\r
1002 }\r
1003 }\r
1004\r
1005 //\r
1006 // Quick out if none were found...\r
1007 //\r
1008 if (NewSize == StrSize(OriginalCommandLine)) {\r
1009 ASSERT(Temp == NULL);\r
1010 Temp = StrnCatGrow(&Temp, NULL, OriginalCommandLine, 0);\r
1011 return (Temp);\r
1012 }\r
1013\r
1014 //\r
1015 // now do the replacements...\r
1016 //\r
1017 NewCommandLine1 = AllocateZeroPool(NewSize);\r
1018 NewCommandLine2 = AllocateZeroPool(NewSize);\r
1019 ItemTemp = AllocateZeroPool(ItemSize+(2*sizeof(CHAR16)));\r
3c865f20 1020 if (NewCommandLine1 == NULL || NewCommandLine2 == NULL || ItemTemp == NULL) {\r
1021 SHELL_FREE_NON_NULL(NewCommandLine1);\r
1022 SHELL_FREE_NON_NULL(NewCommandLine2);\r
1023 SHELL_FREE_NON_NULL(ItemTemp);\r
1024 return (NULL);\r
1025 }\r
a405b86d 1026 StrCpy(NewCommandLine1, OriginalCommandLine);\r
1027 for (MasterEnvList = EfiShellGetEnv(NULL)\r
1028 ; MasterEnvList != NULL && *MasterEnvList != CHAR_NULL //&& *(MasterEnvList+1) != CHAR_NULL\r
1029 ; MasterEnvList += StrLen(MasterEnvList) + 1\r
1030 ){\r
1031 StrCpy(ItemTemp, L"%");\r
1032 StrCat(ItemTemp, MasterEnvList);\r
1033 StrCat(ItemTemp, L"%");\r
1034 ShellCopySearchAndReplace(NewCommandLine1, NewCommandLine2, NewSize, ItemTemp, EfiShellGetEnv(MasterEnvList), TRUE, FALSE);\r
1035 StrCpy(NewCommandLine1, NewCommandLine2);\r
1036 }\r
1037 if (CurrentScriptFile != NULL) {\r
1038 for (AliasListNode = (ALIAS_LIST*)GetFirstNode(&CurrentScriptFile->SubstList)\r
1039 ; !IsNull(&CurrentScriptFile->SubstList, &AliasListNode->Link)\r
1040 ; AliasListNode = (ALIAS_LIST*)GetNextNode(&CurrentScriptFile->SubstList, &AliasListNode->Link)\r
1041 ){\r
1042 ShellCopySearchAndReplace(NewCommandLine1, NewCommandLine2, NewSize, AliasListNode->Alias, AliasListNode->CommandString, TRUE, FALSE);\r
1043 StrCpy(NewCommandLine1, NewCommandLine2);\r
1044 }\r
1045 }\r
1046\r
1047 FreePool(NewCommandLine2);\r
1048 FreePool(ItemTemp);\r
1049\r
1050 return (NewCommandLine1);\r
1051}\r
1052\r
1053/**\r
1054 Internal function to run a command line with pipe usage.\r
1055\r
1056 @param[in] CmdLine The pointer to the command line.\r
1057 @param[in] StdIn The pointer to the Standard input.\r
1058 @param[in] StdOut The pointer to the Standard output.\r
1059\r
1060 @retval EFI_SUCCESS The split command is executed successfully.\r
1061 @retval other Some error occurs when executing the split command.\r
1062**/\r
1063EFI_STATUS\r
1064EFIAPI\r
1065RunSplitCommand(\r
1066 IN CONST CHAR16 *CmdLine,\r
1067 IN SHELL_FILE_HANDLE *StdIn,\r
1068 IN SHELL_FILE_HANDLE *StdOut\r
1069 )\r
1070{\r
1071 EFI_STATUS Status;\r
1072 CHAR16 *NextCommandLine;\r
1073 CHAR16 *OurCommandLine;\r
1074 UINTN Size1;\r
1075 UINTN Size2;\r
1076 SPLIT_LIST *Split;\r
1077 SHELL_FILE_HANDLE *TempFileHandle;\r
1078 BOOLEAN Unicode;\r
1079\r
1080 ASSERT(StdOut == NULL);\r
1081\r
1082 ASSERT(StrStr(CmdLine, L"|") != NULL);\r
1083\r
1084 Status = EFI_SUCCESS;\r
1085 NextCommandLine = NULL;\r
1086 OurCommandLine = NULL;\r
1087 Size1 = 0;\r
1088 Size2 = 0;\r
1089\r
1090 NextCommandLine = StrnCatGrow(&NextCommandLine, &Size1, StrStr(CmdLine, L"|")+1, 0);\r
1091 OurCommandLine = StrnCatGrow(&OurCommandLine , &Size2, CmdLine , StrStr(CmdLine, L"|") - CmdLine);\r
1092 if (NextCommandLine[0] != CHAR_NULL &&\r
1093 NextCommandLine[0] == L'a' &&\r
1094 NextCommandLine[1] == L' '\r
1095 ){\r
1096 CopyMem(NextCommandLine, NextCommandLine+1, StrSize(NextCommandLine) - sizeof(NextCommandLine[0]));\r
1097 Unicode = FALSE;\r
1098 } else {\r
1099 Unicode = TRUE;\r
1100 }\r
1101\r
1102\r
1103 //\r
1104 // make a SPLIT_LIST item and add to list\r
1105 //\r
1106 Split = AllocateZeroPool(sizeof(SPLIT_LIST));\r
1107 ASSERT(Split != NULL);\r
1108 Split->SplitStdIn = StdIn;\r
1109 Split->SplitStdOut = ConvertEfiFileProtocolToShellHandle(CreateFileInterfaceMem(Unicode), NULL);\r
1110 ASSERT(Split->SplitStdOut != NULL);\r
1111 InsertHeadList(&ShellInfoObject.SplitList.Link, &Split->Link);\r
1112\r
1113 ASSERT(StrStr(OurCommandLine, L"|") == NULL);\r
1114 Status = RunCommand(OurCommandLine);\r
1115\r
1116 //\r
1117 // move the output from the first to the in to the second.\r
1118 //\r
1119 TempFileHandle = Split->SplitStdOut;\r
1120 if (Split->SplitStdIn == StdIn) {\r
1121 Split->SplitStdOut = NULL;\r
1122 } else {\r
1123 Split->SplitStdOut = Split->SplitStdIn;\r
1124 }\r
1125 Split->SplitStdIn = TempFileHandle;\r
1126 ShellInfoObject.NewEfiShellProtocol->SetFilePosition(ConvertShellHandleToEfiFileProtocol(Split->SplitStdIn), 0);\r
1127\r
1128 if (!EFI_ERROR(Status)) {\r
1129 Status = RunCommand(NextCommandLine);\r
1130 }\r
1131\r
1132 //\r
1133 // remove the top level from the ScriptList\r
1134 //\r
1135 ASSERT((SPLIT_LIST*)GetFirstNode(&ShellInfoObject.SplitList.Link) == Split);\r
1136 RemoveEntryList(&Split->Link);\r
1137\r
1138 //\r
1139 // Note that the original StdIn is now the StdOut...\r
1140 //\r
1141 if (Split->SplitStdOut != NULL && Split->SplitStdOut != StdIn) {\r
1142 ShellInfoObject.NewEfiShellProtocol->CloseFile(ConvertShellHandleToEfiFileProtocol(Split->SplitStdOut));\r
1143 }\r
1144 if (Split->SplitStdIn != NULL) {\r
1145 ShellInfoObject.NewEfiShellProtocol->CloseFile(ConvertShellHandleToEfiFileProtocol(Split->SplitStdIn));\r
1146 }\r
1147\r
1148 FreePool(Split);\r
1149 FreePool(NextCommandLine);\r
1150 FreePool(OurCommandLine);\r
1151\r
1152 return (Status);\r
1153}\r
1154\r
1155/**\r
1156 Function will process and run a command line.\r
1157\r
1158 This will determine if the command line represents an internal shell \r
1159 command or dispatch an external application.\r
1160\r
1161 @param[in] CmdLine The command line to parse.\r
1162\r
1163 @retval EFI_SUCCESS The command was completed.\r
1164 @retval EFI_ABORTED The command's operation was aborted.\r
1165**/\r
1166EFI_STATUS\r
1167EFIAPI\r
1168RunCommand(\r
1169 IN CONST CHAR16 *CmdLine\r
1170 )\r
1171{\r
1172 EFI_STATUS Status;\r
1173 CHAR16 *CommandName;\r
1174 SHELL_STATUS ShellStatus;\r
1175 UINTN Argc;\r
1176 CHAR16 **Argv;\r
1177 BOOLEAN LastError;\r
1178 CHAR16 LeString[11];\r
1179 CHAR16 *PostAliasCmdLine;\r
1180 UINTN PostAliasSize;\r
1181 CHAR16 *PostVariableCmdLine;\r
1182 CHAR16 *CommandWithPath;\r
1183 EFI_DEVICE_PATH_PROTOCOL *DevPath;\r
1184 CONST CHAR16 *TempLocation;\r
1185 CONST CHAR16 *TempLocation2;\r
1186 SHELL_FILE_HANDLE OriginalStdIn;\r
1187 SHELL_FILE_HANDLE OriginalStdOut;\r
1188 SHELL_FILE_HANDLE OriginalStdErr;\r
1189 CHAR16 *TempLocation3;\r
1190 UINTN Count;\r
1191 UINTN Count2;\r
1192 CHAR16 *CleanOriginal;\r
1193 SPLIT_LIST *Split;\r
1194\r
1195 ASSERT(CmdLine != NULL);\r
1196 if (StrLen(CmdLine) == 0) {\r
1197 return (EFI_SUCCESS);\r
1198 }\r
1199\r
1200 CommandName = NULL;\r
1201 PostVariableCmdLine = NULL;\r
1202 PostAliasCmdLine = NULL;\r
1203 CommandWithPath = NULL;\r
1204 DevPath = NULL;\r
1205 Status = EFI_SUCCESS;\r
1206 CleanOriginal = NULL;\r
1207 Split = NULL;\r
1208\r
1209 CleanOriginal = StrnCatGrow(&CleanOriginal, NULL, CmdLine, 0);\r
1210 while (CleanOriginal[StrLen(CleanOriginal)-1] == L' ') {\r
1211 CleanOriginal[StrLen(CleanOriginal)-1] = CHAR_NULL;\r
1212 }\r
1213 while (CleanOriginal[0] == L' ') {\r
1214 CopyMem(CleanOriginal, CleanOriginal+1, StrSize(CleanOriginal) - sizeof(CleanOriginal[0]));\r
1215 }\r
1216\r
1217 CommandName = NULL;\r
1218 if (StrStr(CleanOriginal, L" ") == NULL){\r
1219 StrnCatGrow(&CommandName, NULL, CleanOriginal, 0);\r
1220 } else {\r
1221 StrnCatGrow(&CommandName, NULL, CleanOriginal, StrStr(CleanOriginal, L" ") - CleanOriginal);\r
1222 }\r
1223\r
1224 ASSERT(PostAliasCmdLine == NULL);\r
1225 if (!ShellCommandIsCommandOnList(CommandName)) {\r
1226 //\r
1227 // Convert via alias\r
1228 //\r
1229 Status = ShellConvertAlias(&CommandName);\r
1230 PostAliasSize = 0;\r
1231 PostAliasCmdLine = StrnCatGrow(&PostAliasCmdLine, &PostAliasSize, CommandName, 0);\r
1232 PostAliasCmdLine = StrnCatGrow(&PostAliasCmdLine, &PostAliasSize, StrStr(CleanOriginal, L" "), 0);\r
1233 ASSERT_EFI_ERROR(Status);\r
1234 } else {\r
1235 PostAliasCmdLine = StrnCatGrow(&PostAliasCmdLine, NULL, CleanOriginal, 0);\r
1236 }\r
1237\r
1238 if (CleanOriginal != NULL) {\r
1239 FreePool(CleanOriginal);\r
1240 CleanOriginal = NULL;\r
1241 }\r
1242\r
1243 if (CommandName != NULL) {\r
1244 FreePool(CommandName);\r
1245 CommandName = NULL;\r
1246 }\r
1247\r
1248 PostVariableCmdLine = ShellConvertVariables(PostAliasCmdLine);\r
1249\r
1250 //\r
1251 // we can now free the modified by alias command line\r
1252 //\r
1253 if (PostAliasCmdLine != NULL) {\r
1254 FreePool(PostAliasCmdLine);\r
1255 PostAliasCmdLine = NULL;\r
1256 }\r
1257\r
3c865f20 1258 if (PostVariableCmdLine == NULL) {\r
1259 return (EFI_OUT_OF_RESOURCES);\r
1260 }\r
1261\r
a405b86d 1262 while (PostVariableCmdLine[StrLen(PostVariableCmdLine)-1] == L' ') {\r
1263 PostVariableCmdLine[StrLen(PostVariableCmdLine)-1] = CHAR_NULL;\r
1264 }\r
1265 while (PostVariableCmdLine[0] == L' ') {\r
1266 CopyMem(PostVariableCmdLine, PostVariableCmdLine+1, StrSize(PostVariableCmdLine) - sizeof(PostVariableCmdLine[0]));\r
1267 }\r
1268\r
1269 //\r
1270 // We dont do normal processing with a split command line (output from one command input to another)\r
1271 //\r
1272 TempLocation3 = NULL;\r
1273 if (StrStr(PostVariableCmdLine, L"|") != NULL) {\r
1274 for (TempLocation3 = PostVariableCmdLine ; TempLocation3 != NULL && *TempLocation3 != CHAR_NULL ; TempLocation3++) {\r
1275 if (*TempLocation3 == L'^' && *(TempLocation3+1) == L'|') {\r
1276 TempLocation3++;\r
1277 } else if (*TempLocation3 == L'|') {\r
1278 break;\r
1279 }\r
1280 }\r
1281 }\r
1282 if (TempLocation3 != NULL && *TempLocation3 != CHAR_NULL) {\r
1283 //\r
1284 // are we in an existing split???\r
1285 //\r
1286 if (!IsListEmpty(&ShellInfoObject.SplitList.Link)) {\r
1287 Split = (SPLIT_LIST*)GetFirstNode(&ShellInfoObject.SplitList.Link);\r
1288 }\r
1289\r
1290 if (Split == NULL) {\r
1291 Status = RunSplitCommand(PostVariableCmdLine, NULL, NULL);\r
1292 } else {\r
1293 Status = RunSplitCommand(PostVariableCmdLine, Split->SplitStdIn, Split->SplitStdOut);\r
1294 }\r
1295 } else {\r
1296\r
1297 //\r
1298 // If this is a mapped drive change handle that...\r
1299 //\r
1300 if (PostVariableCmdLine[(StrLen(PostVariableCmdLine)-1)] == L':' && StrStr(PostVariableCmdLine, L" ") == NULL) {\r
1301 Status = ShellInfoObject.NewEfiShellProtocol->SetCurDir(NULL, PostVariableCmdLine);\r
1302 if (EFI_ERROR(Status)) {\r
1303 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_INVALID_MAPPING), ShellInfoObject.HiiHandle, PostVariableCmdLine);\r
1304 }\r
1305 FreePool(PostVariableCmdLine);\r
1306 return (Status);\r
1307 }\r
1308\r
1309 ///@todo update this section to divide into 3 ways - run internal command, run split (above), and run an external file...\r
1310 /// We waste a lot of time doing processing like StdIn,StdOut,Argv,Argc for things that are external files...\r
1311\r
1312\r
1313\r
1314 Status = UpdateStdInStdOutStdErr(ShellInfoObject.NewShellParametersProtocol, PostVariableCmdLine, &OriginalStdIn, &OriginalStdOut, &OriginalStdErr);\r
1315 if (EFI_ERROR(Status)) {\r
1316 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_INVALID_REDIR), ShellInfoObject.HiiHandle);\r
1317 } else {\r
1318 //\r
1319 // remove the < and/or > from the command line now\r
1320 //\r
1321 for (TempLocation3 = PostVariableCmdLine ; TempLocation3 != NULL && *TempLocation3 != CHAR_NULL ; TempLocation3++) {\r
1322 if (*TempLocation3 == L'^') {\r
1323 if (*(TempLocation3+1) == L'<' || *(TempLocation3+1) == L'>') {\r
1324 CopyMem(TempLocation3, TempLocation3+1, StrSize(TempLocation3) - sizeof(TempLocation3[0]));\r
1325 }\r
1326 } else if (*TempLocation3 == L'>') {\r
1327 *TempLocation3 = CHAR_NULL;\r
1328 } else if ((*TempLocation3 == L'1' || *TempLocation3 == L'2')&&(*(TempLocation3+1) == L'>')) {\r
1329 *TempLocation3 = CHAR_NULL;\r
1330 }\r
1331 }\r
1332\r
1333 while (PostVariableCmdLine[StrLen(PostVariableCmdLine)-1] == L' ') {\r
1334 PostVariableCmdLine[StrLen(PostVariableCmdLine)-1] = CHAR_NULL;\r
1335 }\r
1336 while (PostVariableCmdLine[0] == L' ') {\r
1337 CopyMem(PostVariableCmdLine, PostVariableCmdLine+1, StrSize(PostVariableCmdLine) - sizeof(PostVariableCmdLine[0]));\r
1338 }\r
1339\r
1340 //\r
1341 // get the argc and argv updated for internal commands\r
1342 //\r
1343 Status = UpdateArgcArgv(ShellInfoObject.NewShellParametersProtocol, PostVariableCmdLine, &Argv, &Argc);\r
1344 ASSERT_EFI_ERROR(Status);\r
1345\r
1346 for (Count = 0 ; Count < ShellInfoObject.NewShellParametersProtocol->Argc ; Count++) {\r
1347 if (StrStr(ShellInfoObject.NewShellParametersProtocol->Argv[Count], L"-?") == ShellInfoObject.NewShellParametersProtocol->Argv[Count]\r
1348 || (ShellInfoObject.NewShellParametersProtocol->Argv[0][0] == L'?' && ShellInfoObject.NewShellParametersProtocol->Argv[0][1] == CHAR_NULL)\r
1349 ) {\r
1350 //\r
1351 // We need to redo the arguments since a parameter was -?\r
1352 // move them all down 1 to the end, then up one then replace the first with help\r
1353 //\r
1354 FreePool(ShellInfoObject.NewShellParametersProtocol->Argv[Count]);\r
1355 ShellInfoObject.NewShellParametersProtocol->Argv[Count] = NULL;\r
1356 for (Count2 = Count ; (Count2 + 1) < ShellInfoObject.NewShellParametersProtocol->Argc ; Count2++) {\r
1357 ShellInfoObject.NewShellParametersProtocol->Argv[Count2] = ShellInfoObject.NewShellParametersProtocol->Argv[Count2+1];\r
1358 }\r
1359 ShellInfoObject.NewShellParametersProtocol->Argv[Count2] = NULL;\r
1360 for (Count2 = ShellInfoObject.NewShellParametersProtocol->Argc -1 ; Count2 > 0 ; Count2--) {\r
1361 ShellInfoObject.NewShellParametersProtocol->Argv[Count2] = ShellInfoObject.NewShellParametersProtocol->Argv[Count2-1];\r
1362 }\r
1363 ShellInfoObject.NewShellParametersProtocol->Argv[0] = NULL;\r
1364 ShellInfoObject.NewShellParametersProtocol->Argv[0] = StrnCatGrow(&ShellInfoObject.NewShellParametersProtocol->Argv[0], NULL, L"help", 0);\r
1365 break;\r
1366 }\r
1367 }\r
1368\r
1369 //\r
1370 // command or file?\r
1371 //\r
1372 if (ShellCommandIsCommandOnList(ShellInfoObject.NewShellParametersProtocol->Argv[0])) {\r
1373 //\r
1374 // Run the command (which was converted if it was an alias)\r
1375 //\r
1376 if (!EFI_ERROR(Status)) {\r
1377 Status = ShellCommandRunCommandHandler(ShellInfoObject.NewShellParametersProtocol->Argv[0], &ShellStatus, &LastError);\r
1378 ASSERT_EFI_ERROR(Status);\r
1379 UnicodeSPrint(LeString, sizeof(LeString)*sizeof(LeString[0]), L"0x%08x", ShellStatus);\r
1380 DEBUG_CODE(InternalEfiShellSetEnv(L"DebugLasterror", LeString, TRUE););\r
1381 if (LastError) {\r
1382 InternalEfiShellSetEnv(L"Lasterror", LeString, TRUE);\r
1383 }\r
1384 //\r
1385 // Pass thru the exitcode from the app.\r
1386 //\r
1387 if (ShellCommandGetExit()) {\r
1388 Status = ShellStatus;\r
1389 } else if (ShellStatus != 0 && IsScriptOnlyCommand(ShellInfoObject.NewShellParametersProtocol->Argv[0])) {\r
1390 Status = EFI_ABORTED;\r
1391 }\r
1392 }\r
1393 } else {\r
1394 //\r
1395 // run an external file (or script)\r
1396 //\r
1397 if (StrStr(ShellInfoObject.NewShellParametersProtocol->Argv[0], L":") != NULL) {\r
1398 ASSERT (CommandWithPath == NULL);\r
1399 if (ShellIsFile(ShellInfoObject.NewShellParametersProtocol->Argv[0]) == EFI_SUCCESS) {\r
1400 CommandWithPath = StrnCatGrow(&CommandWithPath, NULL, ShellInfoObject.NewShellParametersProtocol->Argv[0], 0);\r
1401 }\r
1402 }\r
1403 if (CommandWithPath == NULL) {\r
1404 CommandWithPath = ShellFindFilePathEx(ShellInfoObject.NewShellParametersProtocol->Argv[0], mExecutableExtensions);\r
1405 }\r
1406 if (CommandWithPath == NULL || ShellIsDirectory(CommandWithPath) == EFI_SUCCESS) {\r
1407 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_NOT_FOUND), ShellInfoObject.HiiHandle, ShellInfoObject.NewShellParametersProtocol->Argv[0]);\r
1408 } else {\r
1409 //\r
1410 // Check if it's a NSH (script) file.\r
1411 //\r
1412 TempLocation = CommandWithPath+StrLen(CommandWithPath)-4;\r
1413 TempLocation2 = mScriptExtension;\r
1414 if ((StrLen(CommandWithPath) > 4) && (StringNoCaseCompare((VOID*)(&TempLocation), (VOID*)(&TempLocation2)) == 0)) {\r
1415 Status = RunScriptFile (CommandWithPath);\r
1416 } else {\r
1417 DevPath = ShellInfoObject.NewEfiShellProtocol->GetDevicePathFromFilePath(CommandWithPath);\r
1418 ASSERT(DevPath != NULL);\r
1419 Status = InternalShellExecuteDevicePath(\r
1420 &gImageHandle,\r
1421 DevPath,\r
1422 PostVariableCmdLine,\r
1423 NULL,\r
1424 NULL\r
1425 );\r
1426 }\r
1427 }\r
1428 }\r
1429 CommandName = StrnCatGrow(&CommandName, NULL, ShellInfoObject.NewShellParametersProtocol->Argv[0], 0);\r
1430\r
1431 RestoreArgcArgv(ShellInfoObject.NewShellParametersProtocol, &Argv, &Argc);\r
1432\r
1433 RestoreStdInStdOutStdErr(ShellInfoObject.NewShellParametersProtocol, &OriginalStdIn, &OriginalStdOut, &OriginalStdErr);\r
1434 }\r
1435 if (CommandName != NULL) {\r
1436 if (ShellCommandGetCurrentScriptFile() != NULL && !IsScriptOnlyCommand(CommandName)) {\r
1437 //\r
1438 // if this is NOT a scipt only command return success so the script won't quit.\r
1439 // prevent killing the script - this is the only place where we know the actual command name (after alias and variable replacement...)\r
1440 //\r
1441 Status = EFI_SUCCESS;\r
1442 }\r
1443 }\r
1444 }\r
1445\r
1446 SHELL_FREE_NON_NULL(CommandName);\r
1447 SHELL_FREE_NON_NULL(CommandWithPath);\r
1448 SHELL_FREE_NON_NULL(PostVariableCmdLine);\r
1449 SHELL_FREE_NON_NULL(DevPath);\r
1450\r
1451 return (Status);\r
1452}\r
1453\r
1454STATIC CONST UINT16 InvalidChars[] = {L'*', L'?', L'<', L'>', L'\\', L'/', L'\"', 0x0001, 0x0002};\r
1455/**\r
1456 Function determins if the CommandName COULD be a valid command. It does not determine whether\r
1457 this is a valid command. It only checks for invalid characters.\r
1458\r
1459 @param[in] CommandName The name to check\r
1460\r
1461 @retval TRUE CommandName could be a command name\r
1462 @retval FALSE CommandName could not be a valid command name\r
1463**/\r
1464BOOLEAN\r
1465EFIAPI\r
1466IsValidCommandName(\r
1467 IN CONST CHAR16 *CommandName\r
1468 )\r
1469{\r
1470 UINTN Count;\r
1471 if (CommandName == NULL) {\r
1472 ASSERT(FALSE);\r
1473 return (FALSE);\r
1474 }\r
1475 for ( Count = 0\r
1476 ; Count < sizeof(InvalidChars) / sizeof(InvalidChars[0])\r
1477 ; Count++\r
1478 ){\r
1479 if (ScanMem16(CommandName, StrSize(CommandName), InvalidChars[Count]) != NULL) {\r
1480 return (FALSE);\r
1481 }\r
1482 }\r
1483 return (TRUE);\r
1484}\r
1485\r
1486/**\r
1487 Function to process a NSH script file via SHELL_FILE_HANDLE.\r
1488\r
1489 @param[in] Handle The handle to the already opened file.\r
1490 @param[in] Name The name of the script file.\r
1491\r
1492 @retval EFI_SUCCESS the script completed sucessfully\r
1493**/\r
1494EFI_STATUS\r
1495EFIAPI\r
1496RunScriptFileHandle (\r
1497 IN SHELL_FILE_HANDLE Handle,\r
1498 IN CONST CHAR16 *Name\r
1499 )\r
1500{\r
1501 EFI_STATUS Status;\r
1502 SCRIPT_FILE *NewScriptFile;\r
1503 UINTN LoopVar;\r
1504 CHAR16 *CommandLine;\r
1505 CHAR16 *CommandLine2;\r
1506 CHAR16 *CommandLine3;\r
1507 SCRIPT_COMMAND_LIST *LastCommand;\r
1508 BOOLEAN Ascii;\r
1509 BOOLEAN PreScriptEchoState;\r
1510 CONST CHAR16 *CurDir;\r
1511 UINTN LineCount;\r
1512\r
1513 ASSERT(!ShellCommandGetScriptExit());\r
1514\r
1515 PreScriptEchoState = ShellCommandGetEchoState();\r
1516\r
1517 NewScriptFile = (SCRIPT_FILE*)AllocateZeroPool(sizeof(SCRIPT_FILE));\r
3c865f20 1518 if (NewScriptFile == NULL) {\r
1519 return (EFI_OUT_OF_RESOURCES);\r
1520 }\r
a405b86d 1521\r
1522 //\r
1523 // Set up the name\r
1524 //\r
1525 ASSERT(NewScriptFile->ScriptName == NULL);\r
1526 NewScriptFile->ScriptName = StrnCatGrow(&NewScriptFile->ScriptName, NULL, Name, 0);\r
3c865f20 1527 if (NewScriptFile->ScriptName == NULL) {\r
1528 DeleteScriptFileStruct(NewScriptFile);\r
1529 return (EFI_OUT_OF_RESOURCES);\r
1530 }\r
a405b86d 1531\r
1532 //\r
1533 // Save the parameters (used to replace %0 to %9 later on)\r
1534 //\r
1535 NewScriptFile->Argc = ShellInfoObject.NewShellParametersProtocol->Argc;\r
1536 if (NewScriptFile->Argc != 0) {\r
1537 NewScriptFile->Argv = (CHAR16**)AllocateZeroPool(NewScriptFile->Argc * sizeof(CHAR16*));\r
3c865f20 1538 if (NewScriptFile->Argv == NULL) {\r
1539 DeleteScriptFileStruct(NewScriptFile);\r
1540 return (EFI_OUT_OF_RESOURCES);\r
1541 }\r
a405b86d 1542 for (LoopVar = 0 ; LoopVar < 10 && LoopVar < NewScriptFile->Argc; LoopVar++) {\r
1543 ASSERT(NewScriptFile->Argv[LoopVar] == NULL);\r
1544 NewScriptFile->Argv[LoopVar] = StrnCatGrow(&NewScriptFile->Argv[LoopVar], NULL, ShellInfoObject.NewShellParametersProtocol->Argv[LoopVar], 0);\r
3c865f20 1545 if (NewScriptFile->Argv[LoopVar] == NULL) {\r
1546 DeleteScriptFileStruct(NewScriptFile);\r
1547 return (EFI_OUT_OF_RESOURCES);\r
1548 }\r
a405b86d 1549 }\r
1550 } else {\r
1551 NewScriptFile->Argv = NULL;\r
1552 }\r
1553\r
1554 InitializeListHead(&NewScriptFile->CommandList);\r
1555 InitializeListHead(&NewScriptFile->SubstList);\r
1556\r
1557 //\r
1558 // Now build the list of all script commands.\r
1559 //\r
1560 LineCount = 0;\r
1561 while(!ShellFileHandleEof(Handle)) {\r
1562 CommandLine = ShellFileHandleReturnLine(Handle, &Ascii);\r
1563 LineCount++;\r
1564 if (CommandLine == NULL || StrLen(CommandLine) == 0) {\r
1565 continue;\r
1566 }\r
1567 NewScriptFile->CurrentCommand = AllocateZeroPool(sizeof(SCRIPT_COMMAND_LIST));\r
3c865f20 1568 if (NewScriptFile->CurrentCommand == NULL) {\r
1569 DeleteScriptFileStruct(NewScriptFile);\r
1570 return (EFI_OUT_OF_RESOURCES);\r
1571 }\r
a405b86d 1572\r
1573 NewScriptFile->CurrentCommand->Cl = CommandLine;\r
1574 NewScriptFile->CurrentCommand->Data = NULL;\r
1575 NewScriptFile->CurrentCommand->Line = LineCount;\r
1576\r
1577 InsertTailList(&NewScriptFile->CommandList, &NewScriptFile->CurrentCommand->Link);\r
1578 }\r
1579\r
1580 //\r
1581 // Add this as the topmost script file\r
1582 //\r
1583 ShellCommandSetNewScript (NewScriptFile);\r
1584\r
1585 //\r
1586 // Now enumerate through the commands and run each one.\r
1587 //\r
1588 CommandLine = AllocatePool(PcdGet16(PcdShellPrintBufferSize));\r
3c865f20 1589 if (CommandLine == NULL) {\r
1590 DeleteScriptFileStruct(NewScriptFile);\r
1591 return (EFI_OUT_OF_RESOURCES);\r
1592 }\r
a405b86d 1593 CommandLine2 = AllocatePool(PcdGet16(PcdShellPrintBufferSize));\r
3c865f20 1594 if (CommandLine2 == NULL) {\r
1595 FreePool(CommandLine);\r
1596 DeleteScriptFileStruct(NewScriptFile);\r
1597 return (EFI_OUT_OF_RESOURCES);\r
1598 }\r
a405b86d 1599\r
1600 for ( NewScriptFile->CurrentCommand = (SCRIPT_COMMAND_LIST *)GetFirstNode(&NewScriptFile->CommandList)\r
1601 ; !IsNull(&NewScriptFile->CommandList, &NewScriptFile->CurrentCommand->Link)\r
1602 ; // conditional increment in the body of the loop\r
1603 ){\r
3c865f20 1604 ASSERT(CommandLine2 != NULL);\r
a405b86d 1605 StrCpy(CommandLine2, NewScriptFile->CurrentCommand->Cl);\r
1606\r
1607 //\r
1608 // NULL out comments\r
1609 //\r
1610 for (CommandLine3 = CommandLine2 ; CommandLine3 != NULL && *CommandLine3 != CHAR_NULL ; CommandLine3++) {\r
1611 if (*CommandLine3 == L'^') {\r
1612 if (*(CommandLine3+1) == L'#' || *(CommandLine3+1) == L':') {\r
1613 CopyMem(CommandLine3, CommandLine3+1, StrSize(CommandLine3) - sizeof(CommandLine3[0]));\r
1614 }\r
1615 } else if (*CommandLine3 == L'#') {\r
1616 *CommandLine3 = CHAR_NULL;\r
1617 }\r
1618 }\r
1619\r
1620 if (CommandLine2 != NULL && StrLen(CommandLine2) >= 1) {\r
1621 //\r
1622 // Due to variability in starting the find and replace action we need to have both buffers the same.\r
1623 //\r
1624 StrCpy(CommandLine, CommandLine2);\r
1625\r
1626 //\r
1627 // Remove the %0 to %9 from the command line (if we have some arguments)\r
1628 //\r
1629 if (NewScriptFile->Argv != NULL) {\r
1630 switch (NewScriptFile->Argc) {\r
1631 default:\r
1632 Status = ShellCopySearchAndReplace(CommandLine2, CommandLine, PcdGet16 (PcdShellPrintBufferSize), L"%9", NewScriptFile->Argv[9], FALSE, TRUE);\r
1633 ASSERT_EFI_ERROR(Status);\r
1634 case 9:\r
1635 Status = ShellCopySearchAndReplace(CommandLine, CommandLine2, PcdGet16 (PcdShellPrintBufferSize), L"%8", NewScriptFile->Argv[8], FALSE, TRUE);\r
1636 ASSERT_EFI_ERROR(Status);\r
1637 case 8:\r
1638 Status = ShellCopySearchAndReplace(CommandLine2, CommandLine, PcdGet16 (PcdShellPrintBufferSize), L"%7", NewScriptFile->Argv[7], FALSE, TRUE);\r
1639 ASSERT_EFI_ERROR(Status);\r
1640 case 7:\r
1641 Status = ShellCopySearchAndReplace(CommandLine, CommandLine2, PcdGet16 (PcdShellPrintBufferSize), L"%6", NewScriptFile->Argv[6], FALSE, TRUE);\r
1642 ASSERT_EFI_ERROR(Status);\r
1643 case 6:\r
1644 Status = ShellCopySearchAndReplace(CommandLine2, CommandLine, PcdGet16 (PcdShellPrintBufferSize), L"%5", NewScriptFile->Argv[5], FALSE, TRUE);\r
1645 ASSERT_EFI_ERROR(Status);\r
1646 case 5:\r
1647 Status = ShellCopySearchAndReplace(CommandLine, CommandLine2, PcdGet16 (PcdShellPrintBufferSize), L"%4", NewScriptFile->Argv[4], FALSE, TRUE);\r
1648 ASSERT_EFI_ERROR(Status);\r
1649 case 4:\r
1650 Status = ShellCopySearchAndReplace(CommandLine2, CommandLine, PcdGet16 (PcdShellPrintBufferSize), L"%3", NewScriptFile->Argv[3], FALSE, TRUE);\r
1651 ASSERT_EFI_ERROR(Status);\r
1652 case 3:\r
1653 Status = ShellCopySearchAndReplace(CommandLine, CommandLine2, PcdGet16 (PcdShellPrintBufferSize), L"%2", NewScriptFile->Argv[2], FALSE, TRUE);\r
1654 ASSERT_EFI_ERROR(Status);\r
1655 case 2:\r
1656 Status = ShellCopySearchAndReplace(CommandLine2, CommandLine, PcdGet16 (PcdShellPrintBufferSize), L"%1", NewScriptFile->Argv[1], FALSE, TRUE);\r
1657 ASSERT_EFI_ERROR(Status);\r
1658 case 1:\r
1659 Status = ShellCopySearchAndReplace(CommandLine, CommandLine2, PcdGet16 (PcdShellPrintBufferSize), L"%0", NewScriptFile->Argv[0], FALSE, TRUE);\r
1660 ASSERT_EFI_ERROR(Status);\r
1661 break;\r
1662 case 0:\r
1663 break;\r
1664 }\r
1665 }\r
1666 Status = ShellCopySearchAndReplace(CommandLine2, CommandLine, PcdGet16 (PcdShellPrintBufferSize), L"%1", L"\"\"", FALSE, FALSE);\r
1667 Status = ShellCopySearchAndReplace(CommandLine, CommandLine2, PcdGet16 (PcdShellPrintBufferSize), L"%2", L"\"\"", FALSE, FALSE);\r
1668 Status = ShellCopySearchAndReplace(CommandLine2, CommandLine, PcdGet16 (PcdShellPrintBufferSize), L"%3", L"\"\"", FALSE, FALSE);\r
1669 Status = ShellCopySearchAndReplace(CommandLine, CommandLine2, PcdGet16 (PcdShellPrintBufferSize), L"%4", L"\"\"", FALSE, FALSE);\r
1670 Status = ShellCopySearchAndReplace(CommandLine2, CommandLine, PcdGet16 (PcdShellPrintBufferSize), L"%5", L"\"\"", FALSE, FALSE);\r
1671 Status = ShellCopySearchAndReplace(CommandLine, CommandLine2, PcdGet16 (PcdShellPrintBufferSize), L"%6", L"\"\"", FALSE, FALSE);\r
1672 Status = ShellCopySearchAndReplace(CommandLine2, CommandLine, PcdGet16 (PcdShellPrintBufferSize), L"%7", L"\"\"", FALSE, FALSE);\r
1673 Status = ShellCopySearchAndReplace(CommandLine, CommandLine2, PcdGet16 (PcdShellPrintBufferSize), L"%8", L"\"\"", FALSE, FALSE);\r
1674 Status = ShellCopySearchAndReplace(CommandLine2, CommandLine, PcdGet16 (PcdShellPrintBufferSize), L"%9", L"\"\"", FALSE, FALSE);\r
1675\r
1676 StrCpy(CommandLine2, CommandLine);\r
1677\r
1678 LastCommand = NewScriptFile->CurrentCommand;\r
1679\r
1680 for (CommandLine3 = CommandLine2 ; CommandLine3[0] == L' ' ; CommandLine3++);\r
1681\r
3c865f20 1682 if (CommandLine3 != NULL && CommandLine3[0] == L':' ) {\r
a405b86d 1683 //\r
1684 // This line is a goto target / label\r
1685 //\r
1686 } else {\r
1687 if (CommandLine3 != NULL && StrLen(CommandLine3) > 0) {\r
1688 if (ShellCommandGetEchoState()) {\r
1689 CurDir = ShellInfoObject.NewEfiShellProtocol->GetEnv(L"cwd");\r
1690 if (CurDir != NULL && StrLen(CurDir) > 1) {\r
1691 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_CURDIR), ShellInfoObject.HiiHandle, CurDir);\r
1692 } else {\r
1693 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_SHELL), ShellInfoObject.HiiHandle);\r
1694 }\r
1695 ShellPrintEx(-1, -1, L"%s\r\n", CommandLine2);\r
1696 }\r
1697 Status = RunCommand(CommandLine3);\r
1698 }\r
1699\r
1700 if (ShellCommandGetScriptExit()) {\r
1701 ShellCommandRegisterExit(FALSE);\r
1702 Status = EFI_SUCCESS;\r
1703 break;\r
1704 }\r
1705 if (EFI_ERROR(Status)) {\r
1706 break;\r
1707 }\r
1708 if (ShellCommandGetExit()) {\r
1709 break;\r
1710 }\r
1711 }\r
1712 //\r
1713 // If that commend did not update the CurrentCommand then we need to advance it...\r
1714 //\r
1715 if (LastCommand == NewScriptFile->CurrentCommand) {\r
1716 NewScriptFile->CurrentCommand = (SCRIPT_COMMAND_LIST *)GetNextNode(&NewScriptFile->CommandList, &NewScriptFile->CurrentCommand->Link);\r
1717 if (!IsNull(&NewScriptFile->CommandList, &NewScriptFile->CurrentCommand->Link)) {\r
1718 NewScriptFile->CurrentCommand->Reset = TRUE;\r
1719 }\r
1720 }\r
1721 } else {\r
1722 NewScriptFile->CurrentCommand = (SCRIPT_COMMAND_LIST *)GetNextNode(&NewScriptFile->CommandList, &NewScriptFile->CurrentCommand->Link);\r
1723 if (!IsNull(&NewScriptFile->CommandList, &NewScriptFile->CurrentCommand->Link)) {\r
1724 NewScriptFile->CurrentCommand->Reset = TRUE;\r
1725 }\r
1726 }\r
1727 }\r
1728\r
1729 ShellCommandSetEchoState(PreScriptEchoState);\r
1730\r
1731 FreePool(CommandLine);\r
1732 FreePool(CommandLine2);\r
1733 ShellCommandSetNewScript (NULL);\r
1734 return (EFI_SUCCESS);\r
1735}\r
1736\r
1737/**\r
1738 Function to process a NSH script file.\r
1739\r
1740 @param[in] ScriptPath Pointer to the script file name (including file system path).\r
1741\r
1742 @retval EFI_SUCCESS the script completed sucessfully\r
1743**/\r
1744EFI_STATUS\r
1745EFIAPI\r
1746RunScriptFile (\r
1747 IN CONST CHAR16 *ScriptPath\r
1748 )\r
1749{\r
1750 EFI_STATUS Status;\r
1751 SHELL_FILE_HANDLE FileHandle;\r
1752\r
1753 if (ShellIsFile(ScriptPath) != EFI_SUCCESS) {\r
1754 return (EFI_INVALID_PARAMETER);\r
1755 }\r
1756\r
1757 Status = ShellOpenFileByName(ScriptPath, &FileHandle, EFI_FILE_MODE_READ, 0);\r
1758 if (EFI_ERROR(Status)) {\r
1759 return (Status);\r
1760 }\r
1761\r
1762 Status = RunScriptFileHandle(FileHandle, ScriptPath);\r
1763\r
1764 ShellCloseFile(&FileHandle);\r
1765\r
1766 return (Status);\r
1767}\r