ShellPkg/For: Handle memory allocation failure
[mirror_edk2.git] / ShellPkg / Library / UefiShellLevel1CommandsLib / For.c
1 /** @file\r
2   Main file for endfor and for shell level 1 functions.\r
3 \r
4   (C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR>\r
5   Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>\r
6   This program and the accompanying materials\r
7   are licensed and made available under the terms and conditions of the BSD License\r
8   which accompanies this distribution.  The full text of the license may be found at\r
9   http://opensource.org/licenses/bsd-license.php\r
10 \r
11   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13 \r
14 **/\r
15 \r
16 #include "UefiShellLevel1CommandsLib.h"\r
17 #include <Library/PrintLib.h>\r
18 \r
19 /**\r
20   Determine if a valid string is a valid number for the 'for' command.\r
21 \r
22   @param[in] Number The pointer to the string representation of the number to test.\r
23 \r
24   @retval TRUE    The number is valid.\r
25   @retval FALSE   The number is not valid.\r
26 **/\r
27 BOOLEAN\r
28 EFIAPI\r
29 ShellIsValidForNumber (\r
30   IN CONST CHAR16 *Number\r
31   )\r
32 {\r
33   if (Number == NULL || *Number == CHAR_NULL) {\r
34     return (FALSE);\r
35   }\r
36 \r
37   if (*Number == L'-') {\r
38     Number++;\r
39   }\r
40 \r
41   if (StrLen(Number) == 0) {\r
42     return (FALSE);\r
43   }\r
44 \r
45   if (StrLen(Number) >= 7) {\r
46     if ((StrStr(Number, L" ") == NULL) || (((StrStr(Number, L" ") != NULL) && (StrStr(Number, L" ") - Number) >= 7))) {\r
47       return (FALSE);\r
48     }\r
49   }\r
50 \r
51   if (!ShellIsDecimalDigitCharacter(*Number)) {\r
52     return (FALSE);\r
53   }\r
54 \r
55   return (TRUE);\r
56 }\r
57 \r
58 /**\r
59   Function for 'endfor' command.\r
60 \r
61   @param[in] ImageHandle  Handle to the Image (NULL if Internal).\r
62   @param[in] SystemTable  Pointer to the System Table (NULL if Internal).\r
63 **/\r
64 SHELL_STATUS\r
65 EFIAPI\r
66 ShellCommandRunEndFor (\r
67   IN EFI_HANDLE        ImageHandle,\r
68   IN EFI_SYSTEM_TABLE  *SystemTable\r
69   )\r
70 {\r
71   EFI_STATUS          Status;\r
72   BOOLEAN             Found;\r
73   SCRIPT_FILE         *CurrentScriptFile;\r
74 \r
75   Status = CommandInit();\r
76   ASSERT_EFI_ERROR(Status);\r
77 \r
78   if (!gEfiShellProtocol->BatchIsActive()) {\r
79     ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_NO_SCRIPT), gShellLevel1HiiHandle, L"endfor");\r
80     return (SHELL_UNSUPPORTED);\r
81   }\r
82 \r
83   if (gEfiShellParametersProtocol->Argc > 1) {\r
84     ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel1HiiHandle, L"endfor");\r
85     return (SHELL_INVALID_PARAMETER);\r
86   }\r
87 \r
88   Found = MoveToTag(GetPreviousNode, L"for", L"endfor", NULL, ShellCommandGetCurrentScriptFile(), FALSE, FALSE, FALSE);\r
89 \r
90   if (!Found) {\r
91     CurrentScriptFile = ShellCommandGetCurrentScriptFile();\r
92     ShellPrintHiiEx(\r
93       -1, \r
94       -1, \r
95       NULL, \r
96       STRING_TOKEN (STR_SYNTAX_NO_MATCHING), \r
97       gShellLevel1HiiHandle, \r
98       L"For", \r
99       L"EndFor", \r
100       CurrentScriptFile!=NULL\r
101         && CurrentScriptFile->CurrentCommand!=NULL\r
102           ? CurrentScriptFile->CurrentCommand->Line:0);\r
103     return (SHELL_NOT_FOUND);\r
104   }\r
105   return (SHELL_SUCCESS);\r
106 }\r
107 \r
108 typedef struct {\r
109   UINT32          Signature;\r
110   INTN            Current;\r
111   INTN            End;\r
112   INTN            Step;\r
113   CHAR16          *ReplacementName;\r
114   CHAR16          *CurrentValue;\r
115   BOOLEAN         RemoveSubstAlias;\r
116   CHAR16          Set[1];\r
117   } SHELL_FOR_INFO;\r
118 #define SIZE_OF_SHELL_FOR_INFO OFFSET_OF (SHELL_FOR_INFO, Set)\r
119 #define SHELL_FOR_INFO_SIGNATURE SIGNATURE_32 ('S', 'F', 'I', 's')\r
120 \r
121 /**\r
122   Update the value of a given alias on the list.  If the alias is not there then add it.\r
123 \r
124   @param[in] Alias               The alias to test for.\r
125   @param[in] CommandString       The updated command string.\r
126   @param[in, out] List           The list to search.\r
127 \r
128   @retval EFI_SUCCESS           The operation was completed successfully.\r
129   @retval EFI_OUT_OF_RESOURCES  There was not enough free memory.\r
130 **/\r
131 EFI_STATUS\r
132 EFIAPI\r
133 InternalUpdateAliasOnList(\r
134   IN CONST CHAR16       *Alias,\r
135   IN CONST CHAR16       *CommandString,\r
136   IN OUT LIST_ENTRY     *List\r
137   )\r
138 {\r
139   ALIAS_LIST *Node;\r
140   BOOLEAN    Found;\r
141 \r
142   //\r
143   // assert for NULL parameter\r
144   //\r
145   ASSERT(Alias != NULL);\r
146 \r
147   //\r
148   // check for the Alias\r
149   //\r
150   for ( Node = (ALIAS_LIST *)GetFirstNode(List), Found = FALSE\r
151       ; !IsNull(List, &Node->Link)\r
152       ; Node = (ALIAS_LIST *)GetNextNode(List, &Node->Link)\r
153      ){\r
154     ASSERT(Node->CommandString != NULL);\r
155     ASSERT(Node->Alias != NULL);\r
156     if (StrCmp(Node->Alias, Alias)==0) {\r
157       FreePool(Node->CommandString);\r
158       Node->CommandString = NULL;\r
159       Node->CommandString = StrnCatGrow(&Node->CommandString, NULL, CommandString, 0);\r
160       Found = TRUE;\r
161       break;\r
162     }\r
163   }\r
164   if (!Found) {\r
165     Node = AllocateZeroPool(sizeof(ALIAS_LIST));\r
166     if (Node == NULL) {\r
167       return (EFI_OUT_OF_RESOURCES);\r
168     }\r
169     ASSERT(Node->Alias == NULL);\r
170     Node->Alias         = StrnCatGrow(&Node->Alias, NULL, Alias, 0);\r
171     ASSERT(Node->CommandString == NULL);\r
172     Node->CommandString = StrnCatGrow(&Node->CommandString, NULL, CommandString, 0);\r
173     InsertTailList(List, &Node->Link);\r
174   }\r
175   return (EFI_SUCCESS);\r
176 }\r
177 \r
178 /**\r
179   Find out if an alias is on the given list.\r
180 \r
181   @param[in] Alias              The alias to test for.\r
182   @param[in] List               The list to search.\r
183 \r
184   @retval TRUE                  The alias is on the list.\r
185   @retval FALSE                 The alias is not on the list.\r
186 **/\r
187 BOOLEAN\r
188 EFIAPI\r
189 InternalIsAliasOnList(\r
190   IN CONST CHAR16       *Alias,\r
191   IN CONST LIST_ENTRY   *List\r
192   )\r
193 {\r
194   ALIAS_LIST *Node;\r
195 \r
196   //\r
197   // assert for NULL parameter\r
198   //\r
199   ASSERT(Alias != NULL);\r
200 \r
201   //\r
202   // check for the Alias\r
203   //\r
204   for ( Node = (ALIAS_LIST *)GetFirstNode(List)\r
205       ; !IsNull(List, &Node->Link)\r
206       ; Node = (ALIAS_LIST *)GetNextNode(List, &Node->Link)\r
207      ){\r
208     ASSERT(Node->CommandString != NULL);\r
209     ASSERT(Node->Alias != NULL);\r
210     if (StrCmp(Node->Alias, Alias)==0) {\r
211       return (TRUE);\r
212     }\r
213   }\r
214   return (FALSE);\r
215 }\r
216 \r
217 /**\r
218   Remove an alias from the given list.\r
219 \r
220   @param[in] Alias               The alias to remove.\r
221   @param[in, out] List           The list to search.\r
222 **/\r
223 BOOLEAN\r
224 EFIAPI\r
225 InternalRemoveAliasFromList(\r
226   IN CONST CHAR16       *Alias,\r
227   IN OUT LIST_ENTRY     *List\r
228   )\r
229 {\r
230   ALIAS_LIST *Node;\r
231 \r
232   //\r
233   // assert for NULL parameter\r
234   //\r
235   ASSERT(Alias != NULL);\r
236 \r
237   //\r
238   // check for the Alias\r
239   //\r
240   for ( Node = (ALIAS_LIST *)GetFirstNode(List)\r
241       ; !IsNull(List, &Node->Link)\r
242       ; Node = (ALIAS_LIST *)GetNextNode(List, &Node->Link)\r
243      ){\r
244     ASSERT(Node->CommandString != NULL);\r
245     ASSERT(Node->Alias != NULL);\r
246     if (StrCmp(Node->Alias, Alias)==0) {\r
247       RemoveEntryList(&Node->Link);\r
248       FreePool(Node->Alias);\r
249       FreePool(Node->CommandString);\r
250       FreePool(Node);\r
251       return (TRUE);\r
252     }\r
253   }\r
254   return (FALSE);\r
255 }\r
256 \r
257 /**\r
258   Function to determine whether a string is decimal or hex representation of a number\r
259   and return the number converted from the string.\r
260 \r
261   @param[in] String   String representation of a number\r
262 \r
263   @return             the number\r
264   @retval (UINTN)(-1) An error ocurred.\r
265 **/\r
266 UINTN\r
267 EFIAPI\r
268 ReturnUintn(\r
269   IN CONST CHAR16 *String\r
270   )\r
271 {\r
272   UINT64        RetVal;\r
273 \r
274   if (!EFI_ERROR(ShellConvertStringToUint64(String, &RetVal, FALSE, TRUE))) {\r
275     return ((UINTN)RetVal);\r
276   }\r
277   return ((UINTN)(-1));\r
278 }\r
279 \r
280 /**\r
281   Function for 'for' command.\r
282 \r
283   @param[in] ImageHandle  Handle to the Image (NULL if Internal).\r
284   @param[in] SystemTable  Pointer to the System Table (NULL if Internal).\r
285 **/\r
286 SHELL_STATUS\r
287 EFIAPI\r
288 ShellCommandRunFor (\r
289   IN EFI_HANDLE        ImageHandle,\r
290   IN EFI_SYSTEM_TABLE  *SystemTable\r
291   )\r
292 {\r
293   EFI_STATUS          Status;\r
294   SHELL_STATUS        ShellStatus;\r
295   SCRIPT_FILE         *CurrentScriptFile;\r
296   CHAR16              *ArgSet;\r
297   CHAR16              *ArgSetWalker;\r
298   CHAR16              *Parameter;\r
299   UINTN               ArgSize;\r
300   UINTN               LoopVar;\r
301   SHELL_FOR_INFO      *Info;\r
302   CHAR16              *TempString;\r
303   CHAR16              *TempSpot;\r
304   BOOLEAN             FirstPass;\r
305   EFI_SHELL_FILE_INFO *Node;\r
306   EFI_SHELL_FILE_INFO *FileList;\r
307   UINTN               NewSize;\r
308 \r
309   ArgSet              = NULL;\r
310   ArgSize             = 0;\r
311   ShellStatus         = SHELL_SUCCESS;\r
312   ArgSetWalker        = NULL;\r
313   TempString          = NULL;\r
314   Parameter           = NULL;\r
315   FirstPass           = FALSE;\r
316 \r
317   //\r
318   // initialize the shell lib (we must be in non-auto-init...)\r
319   //\r
320   Status = ShellInitialize();\r
321   ASSERT_EFI_ERROR(Status);\r
322 \r
323   Status = CommandInit();\r
324   ASSERT_EFI_ERROR(Status);\r
325 \r
326   if (!gEfiShellProtocol->BatchIsActive()) {\r
327     ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_NO_SCRIPT), gShellLevel1HiiHandle, L"for");\r
328     return (SHELL_UNSUPPORTED);\r
329   }\r
330 \r
331   if (gEfiShellParametersProtocol->Argc < 4) {\r
332     ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellLevel1HiiHandle, L"for");\r
333     return (SHELL_INVALID_PARAMETER);\r
334   }\r
335 \r
336   CurrentScriptFile = ShellCommandGetCurrentScriptFile();\r
337   ASSERT(CurrentScriptFile != NULL);\r
338 \r
339   if ((CurrentScriptFile->CurrentCommand != NULL) && (CurrentScriptFile->CurrentCommand->Data == NULL)) {\r
340     FirstPass = TRUE;\r
341 \r
342     //\r
343     // Make sure that an End exists.\r
344     //\r
345     if (!MoveToTag(GetNextNode, L"endfor", L"for", NULL, CurrentScriptFile, TRUE, TRUE, FALSE)) {\r
346       ShellPrintHiiEx(\r
347         -1, \r
348         -1, \r
349         NULL, \r
350         STRING_TOKEN (STR_SYNTAX_NO_MATCHING), \r
351         gShellLevel1HiiHandle, \r
352         L"EndFor", \r
353         L"For", \r
354         CurrentScriptFile->CurrentCommand->Line);\r
355       return (SHELL_DEVICE_ERROR);\r
356     }\r
357 \r
358     //\r
359     // Process the line.\r
360     //\r
361     if (gEfiShellParametersProtocol->Argv[1][0] != L'%' || gEfiShellParametersProtocol->Argv[1][2] != CHAR_NULL\r
362       ||!((gEfiShellParametersProtocol->Argv[1][1] >= L'a' && gEfiShellParametersProtocol->Argv[1][1] <= L'z')\r
363        ||(gEfiShellParametersProtocol->Argv[1][1] >= L'A' && gEfiShellParametersProtocol->Argv[1][1] <= L'Z'))\r
364      ) {\r
365       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_INV_VAR), gShellLevel1HiiHandle, gEfiShellParametersProtocol->Argv[1]);\r
366       return (SHELL_INVALID_PARAMETER);\r
367     }\r
368 \r
369     if (gUnicodeCollation->StriColl(\r
370         gUnicodeCollation,\r
371         L"in",\r
372         gEfiShellParametersProtocol->Argv[2]) == 0) {\r
373       for (LoopVar = 0x3 ; LoopVar < gEfiShellParametersProtocol->Argc ; LoopVar++) {\r
374         ASSERT((ArgSet == NULL && ArgSize == 0) || (ArgSet != NULL));\r
375         if (StrStr(gEfiShellParametersProtocol->Argv[LoopVar], L"*") != NULL\r
376           ||StrStr(gEfiShellParametersProtocol->Argv[LoopVar], L"?") != NULL\r
377           ||StrStr(gEfiShellParametersProtocol->Argv[LoopVar], L"[") != NULL\r
378           ||StrStr(gEfiShellParametersProtocol->Argv[LoopVar], L"]") != NULL) {\r
379           FileList = NULL;\r
380           Status = ShellOpenFileMetaArg ((CHAR16*)gEfiShellParametersProtocol->Argv[LoopVar], EFI_FILE_MODE_READ, &FileList);\r
381           if (EFI_ERROR(Status) || FileList == NULL || IsListEmpty(&FileList->Link)) {\r
382             ArgSet = StrnCatGrow(&ArgSet, &ArgSize, L" \"", 0);\r
383             ArgSet = StrnCatGrow(&ArgSet, &ArgSize, gEfiShellParametersProtocol->Argv[LoopVar], 0);\r
384             ArgSet = StrnCatGrow(&ArgSet, &ArgSize, L"\"", 0);\r
385           } else {\r
386             for (Node = (EFI_SHELL_FILE_INFO *)GetFirstNode(&FileList->Link)\r
387               ;  !IsNull(&FileList->Link, &Node->Link)\r
388               ;  Node = (EFI_SHELL_FILE_INFO *)GetNextNode(&FileList->Link, &Node->Link)\r
389              ){\r
390               ArgSet = StrnCatGrow(&ArgSet, &ArgSize, L" \"", 0);\r
391               ArgSet = StrnCatGrow(&ArgSet, &ArgSize, Node->FullName, 0);\r
392               ArgSet = StrnCatGrow(&ArgSet, &ArgSize, L"\"", 0);\r
393             }\r
394             ShellCloseFileMetaArg(&FileList);\r
395           }\r
396         } else {\r
397           Parameter = gEfiShellParametersProtocol->Argv[LoopVar];\r
398           if (Parameter[0] == L'\"' && Parameter[StrLen(Parameter)-1] == L'\"') {\r
399             ArgSet = StrnCatGrow(&ArgSet, &ArgSize, L" ", 0);\r
400             ArgSet = StrnCatGrow(&ArgSet, &ArgSize, Parameter, 0);\r
401           } else {\r
402             ArgSet = StrnCatGrow(&ArgSet, &ArgSize, L" \"", 0);\r
403             ArgSet = StrnCatGrow(&ArgSet, &ArgSize, Parameter, 0);\r
404             ArgSet = StrnCatGrow(&ArgSet, &ArgSize, L"\"", 0);\r
405           }\r
406         }\r
407       }\r
408       if (ArgSet == NULL) {\r
409         ShellStatus = SHELL_OUT_OF_RESOURCES;\r
410       } else {\r
411         //\r
412         // set up for an 'in' for loop\r
413         //\r
414         NewSize = StrSize(ArgSet);\r
415         NewSize += sizeof(SHELL_FOR_INFO)+StrSize(gEfiShellParametersProtocol->Argv[1]);\r
416         Info = AllocateZeroPool(NewSize);\r
417         if (Info == NULL) {\r
418           FreePool (ArgSet);\r
419           return SHELL_OUT_OF_RESOURCES;\r
420         }\r
421         Info->Signature = SHELL_FOR_INFO_SIGNATURE;\r
422         CopyMem(Info->Set, ArgSet, StrSize(ArgSet));\r
423         NewSize = StrSize(gEfiShellParametersProtocol->Argv[1]);\r
424         CopyMem(Info->Set+(StrSize(ArgSet)/sizeof(Info->Set[0])), gEfiShellParametersProtocol->Argv[1], NewSize);\r
425         Info->ReplacementName = Info->Set+StrSize(ArgSet)/sizeof(Info->Set[0]);\r
426         Info->CurrentValue  = (CHAR16*)Info->Set;\r
427         Info->Step          = 0;\r
428         Info->Current       = 0;\r
429         Info->End           = 0;\r
430 \r
431         if (InternalIsAliasOnList(Info->ReplacementName, &CurrentScriptFile->SubstList)) {\r
432           Info->RemoveSubstAlias  = FALSE;\r
433         } else {\r
434           Info->RemoveSubstAlias  = TRUE;\r
435         }\r
436         CurrentScriptFile->CurrentCommand->Data = Info;\r
437       }\r
438     } else if (gUnicodeCollation->StriColl(\r
439         gUnicodeCollation,\r
440         L"run",\r
441         gEfiShellParametersProtocol->Argv[2]) == 0) {\r
442       for (LoopVar = 0x3 ; LoopVar < gEfiShellParametersProtocol->Argc ; LoopVar++) {\r
443         ASSERT((ArgSet == NULL && ArgSize == 0) || (ArgSet != NULL));\r
444         if (StrStr (gEfiShellParametersProtocol->Argv[LoopVar], L")") != NULL &&\r
445             (LoopVar + 1) < gEfiShellParametersProtocol->Argc\r
446            ) {\r
447           return (SHELL_INVALID_PARAMETER);\r
448         }\r
449         if (ArgSet == NULL) {\r
450 //        ArgSet = StrnCatGrow(&ArgSet, &ArgSize, L"\"", 0);\r
451         } else {\r
452           ArgSet = StrnCatGrow(&ArgSet, &ArgSize, L" ", 0);\r
453         }\r
454         ArgSet = StrnCatGrow(&ArgSet, &ArgSize, gEfiShellParametersProtocol->Argv[LoopVar], 0);\r
455 //        ArgSet = StrnCatGrow(&ArgSet, &ArgSize, L" ", 0);\r
456       }\r
457       if (ArgSet == NULL) {\r
458         ShellStatus = SHELL_OUT_OF_RESOURCES;\r
459       } else {\r
460         //\r
461         // set up for a 'run' for loop\r
462         //\r
463         Info = AllocateZeroPool(sizeof(SHELL_FOR_INFO)+StrSize(gEfiShellParametersProtocol->Argv[1]));\r
464         if (Info == NULL) {\r
465           FreePool (ArgSet);\r
466           return SHELL_OUT_OF_RESOURCES;\r
467         }\r
468         Info->Signature = SHELL_FOR_INFO_SIGNATURE;\r
469         CopyMem(Info->Set, gEfiShellParametersProtocol->Argv[1], StrSize(gEfiShellParametersProtocol->Argv[1]));\r
470         Info->ReplacementName = Info->Set;\r
471         Info->CurrentValue    = NULL;\r
472         ArgSetWalker            = ArgSet;\r
473         if (ArgSetWalker[0] != L'(') {\r
474           ShellPrintHiiEx(\r
475             -1, \r
476             -1, \r
477             NULL, \r
478             STRING_TOKEN (STR_GEN_PROBLEM_SCRIPT), \r
479             gShellLevel1HiiHandle, \r
480             ArgSet, \r
481             CurrentScriptFile->CurrentCommand->Line);\r
482           ShellStatus = SHELL_INVALID_PARAMETER;\r
483         } else {\r
484           TempSpot = StrStr(ArgSetWalker, L")");\r
485           if (TempSpot != NULL) {\r
486             TempString = TempSpot+1;\r
487             if (*(TempString) != CHAR_NULL) {\r
488               while(TempString != NULL && *TempString == L' ') {\r
489                 TempString++;\r
490               }\r
491               if (StrLen(TempString) > 0) {\r
492                 TempSpot = NULL;\r
493               }\r
494             }\r
495           }\r
496           if (TempSpot == NULL) {\r
497             ShellPrintHiiEx(\r
498               -1, \r
499               -1, \r
500               NULL, \r
501               STRING_TOKEN (STR_GEN_PROBLEM_SCRIPT), \r
502               gShellLevel1HiiHandle, \r
503               CurrentScriptFile->CurrentCommand->Line);\r
504             ShellStatus = SHELL_INVALID_PARAMETER;\r
505           } else {\r
506             *TempSpot = CHAR_NULL;\r
507             ArgSetWalker++;\r
508             while (ArgSetWalker != NULL && ArgSetWalker[0] == L' ') {\r
509               ArgSetWalker++;\r
510             }\r
511             if (!ShellIsValidForNumber(ArgSetWalker)) {\r
512               ShellPrintHiiEx(\r
513                 -1, \r
514                 -1, \r
515                 NULL, \r
516                 STRING_TOKEN (STR_GEN_PROBLEM_SCRIPT), \r
517                 gShellLevel1HiiHandle, \r
518                 ArgSet, \r
519                 CurrentScriptFile->CurrentCommand->Line);\r
520               ShellStatus = SHELL_INVALID_PARAMETER;\r
521             } else {\r
522               if (ArgSetWalker[0] == L'-') {\r
523                 Info->Current = 0 - (INTN)ReturnUintn(ArgSetWalker+1);\r
524               } else {\r
525                 Info->Current = (INTN)ReturnUintn(ArgSetWalker);\r
526               }\r
527               ArgSetWalker  = StrStr(ArgSetWalker, L" ");\r
528               while (ArgSetWalker != NULL && ArgSetWalker[0] == L' ') {\r
529                 ArgSetWalker++;\r
530               }\r
531               if (ArgSetWalker == NULL || *ArgSetWalker == CHAR_NULL || !ShellIsValidForNumber(ArgSetWalker)){\r
532                 ShellPrintHiiEx(\r
533                   -1, \r
534                   -1, \r
535                   NULL, \r
536                   STRING_TOKEN (STR_GEN_PROBLEM_SCRIPT), \r
537                   gShellLevel1HiiHandle, \r
538                   ArgSet, \r
539                   CurrentScriptFile->CurrentCommand->Line);\r
540                 ShellStatus = SHELL_INVALID_PARAMETER;\r
541               } else {\r
542                 if (ArgSetWalker[0] == L'-') {\r
543                   Info->End = 0 - (INTN)ReturnUintn(ArgSetWalker+1);\r
544                 } else {\r
545                   Info->End = (INTN)ReturnUintn(ArgSetWalker);\r
546                 }\r
547                 if (Info->Current < Info->End) {\r
548                   Info->Step            = 1;\r
549                 } else {\r
550                   Info->Step            = -1;\r
551                 }\r
552 \r
553                 ArgSetWalker  = StrStr(ArgSetWalker, L" ");\r
554                 while (ArgSetWalker != NULL && ArgSetWalker[0] == L' ') {\r
555                   ArgSetWalker++;\r
556                 }\r
557                 if (ArgSetWalker != NULL && *ArgSetWalker != CHAR_NULL) {\r
558                   if (ArgSetWalker == NULL || *ArgSetWalker == CHAR_NULL || !ShellIsValidForNumber(ArgSetWalker)){\r
559                     ShellPrintHiiEx(\r
560                       -1, \r
561                       -1, \r
562                       NULL, \r
563                       STRING_TOKEN (STR_GEN_PROBLEM_SCRIPT), \r
564                       gShellLevel1HiiHandle, \r
565                       ArgSet, \r
566                       CurrentScriptFile->CurrentCommand->Line);\r
567                     ShellStatus = SHELL_INVALID_PARAMETER;\r
568                   } else {\r
569                     if (*ArgSetWalker == L')') {\r
570                       ASSERT(Info->Step == 1 || Info->Step == -1);\r
571                     } else {\r
572                       if (ArgSetWalker[0] == L'-') {\r
573                         Info->Step = 0 - (INTN)ReturnUintn(ArgSetWalker+1);\r
574                       } else {\r
575                         Info->Step = (INTN)ReturnUintn(ArgSetWalker);\r
576                       }\r
577 \r
578                       if (StrStr(ArgSetWalker, L" ") != NULL) {\r
579                         ShellPrintHiiEx(\r
580                           -1, \r
581                           -1, \r
582                           NULL, \r
583                           STRING_TOKEN (STR_GEN_PROBLEM_SCRIPT), \r
584                           gShellLevel1HiiHandle, \r
585                           ArgSet, \r
586                           CurrentScriptFile->CurrentCommand->Line);\r
587                         ShellStatus = SHELL_INVALID_PARAMETER;\r
588                       }\r
589                     }\r
590                   }\r
591                   \r
592                 }\r
593               }\r
594             }\r
595           }\r
596         }\r
597         if (ShellStatus == SHELL_SUCCESS) {\r
598           if (InternalIsAliasOnList(Info->ReplacementName, &CurrentScriptFile->SubstList)) {\r
599             Info->RemoveSubstAlias  = FALSE;\r
600           } else {\r
601             Info->RemoveSubstAlias  = TRUE;\r
602           }\r
603         }\r
604         if (CurrentScriptFile->CurrentCommand != NULL) {\r
605           CurrentScriptFile->CurrentCommand->Data = Info;\r
606         }\r
607       }\r
608     } else {\r
609       ShellPrintHiiEx(\r
610         -1, \r
611         -1, \r
612         NULL, \r
613         STRING_TOKEN (STR_GEN_PROBLEM_SCRIPT), \r
614         gShellLevel1HiiHandle, \r
615         ArgSet, \r
616         CurrentScriptFile!=NULL \r
617           && CurrentScriptFile->CurrentCommand!=NULL\r
618           ? CurrentScriptFile->CurrentCommand->Line:0);\r
619       ShellStatus = SHELL_INVALID_PARAMETER;\r
620     }\r
621   } else {\r
622     //\r
623     // These need to be NULL since they are used to determine if this is the first pass later on...\r
624     //\r
625     ASSERT(ArgSetWalker == NULL);\r
626     ASSERT(ArgSet       == NULL);\r
627   }\r
628 \r
629   if (CurrentScriptFile != NULL && CurrentScriptFile->CurrentCommand != NULL) {\r
630     Info = (SHELL_FOR_INFO*)CurrentScriptFile->CurrentCommand->Data;\r
631     if (CurrentScriptFile->CurrentCommand->Reset) {\r
632       Info->CurrentValue  = (CHAR16*)Info->Set;\r
633       FirstPass = TRUE;\r
634       CurrentScriptFile->CurrentCommand->Reset = FALSE;\r
635     }\r
636   } else {\r
637     ShellStatus = SHELL_UNSUPPORTED;\r
638     Info = NULL;\r
639   }\r
640   if (ShellStatus == SHELL_SUCCESS) {\r
641     ASSERT(Info != NULL);\r
642     if (Info->Step != 0) {\r
643       //\r
644       // only advance if not the first pass\r
645       //\r
646       if (!FirstPass) {\r
647         //\r
648         // sequence version of for loop...\r
649         //\r
650         Info->Current += Info->Step;\r
651       }\r
652 \r
653       TempString = AllocateZeroPool(50*sizeof(CHAR16));\r
654       UnicodeSPrint(TempString, 50*sizeof(CHAR16), L"%d", Info->Current);\r
655       InternalUpdateAliasOnList(Info->ReplacementName, TempString, &CurrentScriptFile->SubstList);\r
656       FreePool(TempString);\r
657 \r
658       if ((Info->Step > 0 && Info->Current > Info->End) || (Info->Step < 0 && Info->Current < Info->End)) {\r
659         CurrentScriptFile->CurrentCommand->Data = NULL;\r
660         //\r
661         // find the matching endfor (we're done with the loop)\r
662         //\r
663         if (!MoveToTag(GetNextNode, L"endfor", L"for", NULL, CurrentScriptFile, TRUE, FALSE, FALSE)) {\r
664           ShellPrintHiiEx(\r
665             -1, \r
666             -1, \r
667             NULL, \r
668             STRING_TOKEN (STR_SYNTAX_NO_MATCHING), \r
669             gShellLevel1HiiHandle, \r
670             L"EndFor", \r
671             L"For", \r
672             CurrentScriptFile!=NULL \r
673               && CurrentScriptFile->CurrentCommand!=NULL\r
674               ? CurrentScriptFile->CurrentCommand->Line:0);\r
675           ShellStatus = SHELL_DEVICE_ERROR;\r
676         }\r
677         if (Info->RemoveSubstAlias) {\r
678           //\r
679           // remove item from list\r
680           //\r
681           InternalRemoveAliasFromList(Info->ReplacementName, &CurrentScriptFile->SubstList);\r
682         }\r
683         FreePool(Info);\r
684       }\r
685     } else {\r
686       //\r
687       // Must be in 'in' version of for loop...\r
688       //\r
689       ASSERT(Info->Set != NULL);\r
690       if (Info->CurrentValue != NULL && *Info->CurrentValue != CHAR_NULL) {\r
691         if (Info->CurrentValue[0] == L' ') {\r
692           Info->CurrentValue++;\r
693         }\r
694         if (Info->CurrentValue[0] == L'\"') {\r
695           Info->CurrentValue++;\r
696         }\r
697         //\r
698         // do the next one of the set\r
699         //\r
700         ASSERT(TempString == NULL);\r
701         TempString = StrnCatGrow(&TempString, NULL, Info->CurrentValue, 0);\r
702         if (TempString == NULL) {\r
703           ShellStatus = SHELL_OUT_OF_RESOURCES;\r
704         } else {\r
705           TempSpot   = StrStr(TempString, L"\" \"");\r
706           if (TempSpot != NULL) {\r
707             *TempSpot = CHAR_NULL;\r
708           }\r
709           while (TempString[StrLen(TempString)-1] == L'\"') {\r
710             TempString[StrLen(TempString)-1] = CHAR_NULL;\r
711           }\r
712           InternalUpdateAliasOnList(Info->ReplacementName, TempString, &CurrentScriptFile->SubstList);\r
713           Info->CurrentValue += StrLen(TempString);\r
714 \r
715           if (Info->CurrentValue[0] == L'\"') {\r
716             Info->CurrentValue++;\r
717           }\r
718           FreePool(TempString);\r
719         }\r
720       } else {\r
721         CurrentScriptFile->CurrentCommand->Data = NULL;\r
722         //\r
723         // find the matching endfor (we're done with the loop)\r
724         //\r
725         if (!MoveToTag(GetNextNode, L"endfor", L"for", NULL, CurrentScriptFile, TRUE, FALSE, FALSE)) {\r
726           ShellPrintHiiEx(\r
727             -1, \r
728             -1, \r
729             NULL, \r
730             STRING_TOKEN (STR_SYNTAX_NO_MATCHING), \r
731             gShellLevel1HiiHandle, \r
732             L"EndFor", \r
733             L"For", \r
734             CurrentScriptFile!=NULL \r
735               && CurrentScriptFile->CurrentCommand!=NULL\r
736               ? CurrentScriptFile->CurrentCommand->Line:0);\r
737           ShellStatus = SHELL_DEVICE_ERROR;\r
738         }\r
739         if (Info->RemoveSubstAlias) {\r
740           //\r
741           // remove item from list\r
742           //\r
743           InternalRemoveAliasFromList(Info->ReplacementName, &CurrentScriptFile->SubstList);\r
744         }\r
745         FreePool(Info);\r
746       }\r
747     }\r
748   }\r
749   if (ArgSet != NULL) {\r
750     FreePool(ArgSet);\r
751   }\r
752   return (ShellStatus);\r
753 }\r
754 \r