Verify memory allocations were successful.
[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   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 "UefiShellLevel1CommandsLib.h"\r
16 #include <Library/PrintLib.h>\r
17 \r
18 BOOLEAN\r
19 EFIAPI\r
20 ShellIsValidForNumber (\r
21   IN CONST CHAR16 *Number\r
22   )\r
23 {\r
24   if (Number == NULL || *Number == CHAR_NULL) {\r
25     return (FALSE);\r
26   }\r
27 \r
28   if (*Number == L'-') {\r
29     Number++;\r
30   }\r
31 \r
32   if (StrLen(Number) == 0) {\r
33     return (FALSE);\r
34   }\r
35 \r
36   if (StrLen(Number) >= 7) {\r
37     if (StrStr(Number, L" ") != NULL && (StrStr(Number, L" ") - Number) >= 7) {\r
38       return (FALSE);\r
39     }\r
40   }\r
41 \r
42   if (!ShellIsDecimalDigitCharacter(*Number)) {\r
43     return (FALSE);\r
44   }\r
45 \r
46   return (TRUE);\r
47 }\r
48 \r
49 /**\r
50   Function for 'endfor' command.\r
51 \r
52   @param[in] ImageHandle  Handle to the Image (NULL if Internal).\r
53   @param[in] SystemTable  Pointer to the System Table (NULL if Internal).\r
54 **/\r
55 SHELL_STATUS\r
56 EFIAPI\r
57 ShellCommandRunEndFor (\r
58   IN EFI_HANDLE        ImageHandle,\r
59   IN EFI_SYSTEM_TABLE  *SystemTable\r
60   )\r
61 {\r
62   EFI_STATUS          Status;\r
63   BOOLEAN             Found;\r
64 \r
65   Status = CommandInit();\r
66   ASSERT_EFI_ERROR(Status);\r
67 \r
68   if (!gEfiShellProtocol->BatchIsActive()) {\r
69     ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_NO_SCRIPT), gShellLevel1HiiHandle, L"EndFor");\r
70     return (SHELL_UNSUPPORTED);\r
71   }\r
72 \r
73   if (gEfiShellParametersProtocol->Argc > 1) {\r
74     ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel1HiiHandle);\r
75     return (SHELL_INVALID_PARAMETER);\r
76   }\r
77 \r
78   Found = MoveToTag(GetPreviousNode, L"for", L"endfor", NULL, ShellCommandGetCurrentScriptFile(), FALSE, FALSE, FALSE);\r
79 \r
80   if (!Found) {\r
81     ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_NO_MATCHING), gShellLevel1HiiHandle, L"For", L"EndFor", ShellCommandGetCurrentScriptFile()->CurrentCommand->Line);\r
82     return (SHELL_NOT_FOUND);\r
83   }\r
84   return (SHELL_SUCCESS);\r
85 }\r
86 \r
87 typedef struct {\r
88   UINT32          Signature;\r
89   INTN            Current;\r
90   INTN            End;\r
91   INTN            Step;\r
92   CHAR16          *ReplacementName;\r
93   CHAR16          *CurrentValue;\r
94   BOOLEAN         RemoveSubstAlias;\r
95   CHAR16          Set[1];\r
96   } SHELL_FOR_INFO;\r
97 #define SIZE_OF_SHELL_FOR_INFO OFFSET_OF (SHELL_FOR_INFO, Set)\r
98 #define SHELL_FOR_INFO_SIGNATURE SIGNATURE_32 ('S', 'F', 'I', 's')\r
99 \r
100 /**\r
101   Update the value of a given alias on the list.  If the alias is not there then add it.\r
102 \r
103   @param[in] Alias              The alias to test for.\r
104   @param[in] CommandString      The updated command string.\r
105   @param[in,out] List           The list to search.\r
106 \r
107   @retval EFI_SUCCESS           The operation was completed successfully.\r
108   @retval EFI_OUT_OF_RESOURCES  There was not enough free memory.\r
109 **/\r
110 EFI_STATUS\r
111 EFIAPI\r
112 InternalUpdateAliasOnList(\r
113   IN CONST CHAR16       *Alias,\r
114   IN CONST CHAR16       *CommandString,\r
115   IN OUT LIST_ENTRY     *List\r
116   )\r
117 {\r
118   ALIAS_LIST *Node;\r
119   BOOLEAN    Found;\r
120 \r
121   //\r
122   // assert for NULL parameter\r
123   //\r
124   ASSERT(Alias != NULL);\r
125 \r
126   //\r
127   // check for the Alias\r
128   //\r
129   for ( Node = (ALIAS_LIST *)GetFirstNode(List), Found = FALSE\r
130       ; !IsNull(List, &Node->Link)\r
131       ; Node = (ALIAS_LIST *)GetNextNode(List, &Node->Link)\r
132      ){\r
133     ASSERT(Node->CommandString != NULL);\r
134     ASSERT(Node->Alias != NULL);\r
135     if (StrCmp(Node->Alias, Alias)==0) {\r
136       FreePool(Node->CommandString);\r
137       Node->CommandString = NULL;\r
138       Node->CommandString = StrnCatGrow(&Node->CommandString, NULL, CommandString, 0);\r
139       Found = TRUE;\r
140       break;\r
141     }\r
142   }\r
143   if (!Found) {\r
144     Node = AllocateZeroPool(sizeof(ALIAS_LIST));\r
145     if (Node == NULL) {\r
146       return (EFI_OUT_OF_RESOURCES);\r
147     }\r
148     ASSERT(Node->Alias == NULL);\r
149     Node->Alias         = StrnCatGrow(&Node->Alias, NULL, Alias, 0);\r
150     ASSERT(Node->CommandString == NULL);\r
151     Node->CommandString = StrnCatGrow(&Node->CommandString, NULL, CommandString, 0);\r
152     InsertTailList(List, &Node->Link);\r
153   }\r
154   return (EFI_SUCCESS);\r
155 }\r
156 \r
157 /**\r
158   Find out if an alias is on the given list.\r
159 \r
160   @param[in] Alias              The alias to test for.\r
161   @param[in] List               The list to search.\r
162 \r
163   @retval TRUE                  The alias is on the list.\r
164   @retval FALSE                 The alias is not on the list.\r
165 **/\r
166 BOOLEAN\r
167 EFIAPI\r
168 InternalIsAliasOnList(\r
169   IN CONST CHAR16       *Alias,\r
170   IN CONST LIST_ENTRY   *List\r
171   )\r
172 {\r
173   ALIAS_LIST *Node;\r
174 \r
175   //\r
176   // assert for NULL parameter\r
177   //\r
178   ASSERT(Alias != NULL);\r
179 \r
180   //\r
181   // check for the Alias\r
182   //\r
183   for ( Node = (ALIAS_LIST *)GetFirstNode(List)\r
184       ; !IsNull(List, &Node->Link)\r
185       ; Node = (ALIAS_LIST *)GetNextNode(List, &Node->Link)\r
186      ){\r
187     ASSERT(Node->CommandString != NULL);\r
188     ASSERT(Node->Alias != NULL);\r
189     if (StrCmp(Node->Alias, Alias)==0) {\r
190       return (TRUE);\r
191     }\r
192   }\r
193   return (FALSE);\r
194 }\r
195 \r
196 /**\r
197   Remove an alias from the given list.\r
198 \r
199   @param[in] Alias              The alias to remove.\r
200   @param[in,out] List           The list to search.\r
201 **/\r
202 BOOLEAN\r
203 EFIAPI\r
204 InternalRemoveAliasFromList(\r
205   IN CONST CHAR16       *Alias,\r
206   IN OUT LIST_ENTRY     *List\r
207   )\r
208 {\r
209   ALIAS_LIST *Node;\r
210 \r
211   //\r
212   // assert for NULL parameter\r
213   //\r
214   ASSERT(Alias != NULL);\r
215 \r
216   //\r
217   // check for the Alias\r
218   //\r
219   for ( Node = (ALIAS_LIST *)GetFirstNode(List)\r
220       ; !IsNull(List, &Node->Link)\r
221       ; Node = (ALIAS_LIST *)GetNextNode(List, &Node->Link)\r
222      ){\r
223     ASSERT(Node->CommandString != NULL);\r
224     ASSERT(Node->Alias != NULL);\r
225     if (StrCmp(Node->Alias, Alias)==0) {\r
226       RemoveEntryList(&Node->Link);\r
227       FreePool(Node->Alias);\r
228       FreePool(Node->CommandString);\r
229       FreePool(Node);\r
230       return (TRUE);\r
231     }\r
232   }\r
233   return (FALSE);\r
234 }\r
235 \r
236 /**\r
237   Function for 'for' command.\r
238 \r
239   @param[in] ImageHandle  Handle to the Image (NULL if Internal).\r
240   @param[in] SystemTable  Pointer to the System Table (NULL if Internal).\r
241 **/\r
242 SHELL_STATUS\r
243 EFIAPI\r
244 ShellCommandRunFor (\r
245   IN EFI_HANDLE        ImageHandle,\r
246   IN EFI_SYSTEM_TABLE  *SystemTable\r
247   )\r
248 {\r
249   EFI_STATUS          Status;\r
250   SHELL_STATUS        ShellStatus;\r
251   SCRIPT_FILE         *CurrentScriptFile;\r
252   CHAR16              *ArgSet;\r
253   CHAR16              *ArgSetWalker;\r
254   UINTN               ArgSize;\r
255   UINTN               LoopVar;\r
256   SHELL_FOR_INFO      *Info;\r
257   CHAR16              *TempString;\r
258   CHAR16              *TempSpot;\r
259   BOOLEAN             FirstPass;\r
260   EFI_SHELL_FILE_INFO *Node;\r
261   EFI_SHELL_FILE_INFO *FileList;\r
262   UINTN               NewSize;\r
263 \r
264   ArgSet              = NULL;\r
265   ArgSize             = 0;\r
266   ShellStatus         = SHELL_SUCCESS;\r
267   ArgSetWalker        = NULL;\r
268   TempString          = NULL;\r
269   FirstPass           = FALSE;\r
270 \r
271   //\r
272   // initialize the shell lib (we must be in non-auto-init...)\r
273   //\r
274   Status = ShellInitialize();\r
275   ASSERT_EFI_ERROR(Status);\r
276 \r
277   Status = CommandInit();\r
278   ASSERT_EFI_ERROR(Status);\r
279 \r
280   if (!gEfiShellProtocol->BatchIsActive()) {\r
281     ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_NO_SCRIPT), gShellLevel1HiiHandle, L"For");\r
282     return (SHELL_UNSUPPORTED);\r
283   }\r
284 \r
285   if (gEfiShellParametersProtocol->Argc < 4) {\r
286     ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellLevel1HiiHandle);\r
287     return (SHELL_INVALID_PARAMETER);\r
288   }\r
289 \r
290   CurrentScriptFile = ShellCommandGetCurrentScriptFile();\r
291   ASSERT(CurrentScriptFile != NULL);\r
292 \r
293   if (CurrentScriptFile->CurrentCommand->Data == NULL) {\r
294     FirstPass = TRUE;\r
295 \r
296     //\r
297     // Make sure that an End exists.\r
298     //\r
299     if (!MoveToTag(GetNextNode, L"endfor", L"for", NULL, CurrentScriptFile, TRUE, TRUE, FALSE)) {\r
300       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_NO_MATCHING), gShellLevel1HiiHandle, L"EndFor", L"For", ShellCommandGetCurrentScriptFile()->CurrentCommand->Line);\r
301       return (SHELL_DEVICE_ERROR);\r
302     }\r
303 \r
304     //\r
305     // Process the line.\r
306     //\r
307     if (gEfiShellParametersProtocol->Argv[1][0] != L'%' || gEfiShellParametersProtocol->Argv[1][2] != CHAR_NULL\r
308       ||!((gEfiShellParametersProtocol->Argv[1][1] >= L'a' && gEfiShellParametersProtocol->Argv[1][1] <= L'z')\r
309        ||(gEfiShellParametersProtocol->Argv[1][1] >= L'A' && gEfiShellParametersProtocol->Argv[1][1] <= L'Z'))\r
310      ) {\r
311       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_INV_VAR), gShellLevel1HiiHandle, gEfiShellParametersProtocol->Argv[2]);\r
312       return (SHELL_INVALID_PARAMETER);\r
313     }\r
314 \r
315     if (gUnicodeCollation->StriColl(\r
316         gUnicodeCollation,\r
317         L"in",\r
318         gEfiShellParametersProtocol->Argv[2]) == 0) {\r
319       for (LoopVar = 0x3 ; LoopVar < gEfiShellParametersProtocol->Argc ; LoopVar++) {\r
320         ASSERT((ArgSet == NULL && ArgSize == 0) || (ArgSet != NULL));\r
321         if (ArgSet == NULL) {\r
322   //        ArgSet = StrnCatGrow(&ArgSet, &ArgSize, L"\"", 0);\r
323         } else {\r
324           ArgSet = StrnCatGrow(&ArgSet, &ArgSize, L" \"", 0);\r
325         }\r
326         if (StrStr(gEfiShellParametersProtocol->Argv[LoopVar], L"*") != NULL\r
327           ||StrStr(gEfiShellParametersProtocol->Argv[LoopVar], L"?") != NULL\r
328           ||StrStr(gEfiShellParametersProtocol->Argv[LoopVar], L"[") != NULL\r
329           ||StrStr(gEfiShellParametersProtocol->Argv[LoopVar], L"]") != NULL) {\r
330           FileList = NULL;\r
331           Status = ShellOpenFileMetaArg ((CHAR16*)gEfiShellParametersProtocol->Argv[LoopVar], EFI_FILE_MODE_READ, &FileList);\r
332           if (EFI_ERROR(Status) || FileList == NULL || IsListEmpty(&FileList->Link)) {\r
333             ArgSet = StrnCatGrow(&ArgSet, &ArgSize, gEfiShellParametersProtocol->Argv[LoopVar], 0);\r
334           } else {\r
335             for (Node = (EFI_SHELL_FILE_INFO *)GetFirstNode(&FileList->Link)\r
336               ;  !IsNull(&FileList->Link, &Node->Link)\r
337               ;  Node = (EFI_SHELL_FILE_INFO *)GetNextNode(&FileList->Link, &Node->Link)\r
338              ){\r
339               ArgSet = StrnCatGrow(&ArgSet, &ArgSize, L" \"", 0);\r
340               ArgSet = StrnCatGrow(&ArgSet, &ArgSize, Node->FullName, 0);\r
341               ArgSet = StrnCatGrow(&ArgSet, &ArgSize, L"\"", 0);\r
342             }\r
343             ShellCloseFileMetaArg(&FileList);\r
344           }\r
345         } else {\r
346           ArgSet = StrnCatGrow(&ArgSet, &ArgSize, gEfiShellParametersProtocol->Argv[LoopVar], 0);\r
347         }\r
348         ArgSet = StrnCatGrow(&ArgSet, &ArgSize, L"\"", 0);\r
349       }\r
350       //\r
351       // set up for an 'in' for loop\r
352       //\r
353       NewSize = StrSize(ArgSet);\r
354       NewSize += sizeof(SHELL_FOR_INFO)+StrSize(gEfiShellParametersProtocol->Argv[1]);\r
355       Info = AllocateZeroPool(NewSize);\r
356       ASSERT(Info != NULL);\r
357       Info->Signature = SHELL_FOR_INFO_SIGNATURE;\r
358       CopyMem(Info->Set, ArgSet, StrSize(ArgSet));\r
359       NewSize = StrSize(gEfiShellParametersProtocol->Argv[1]);\r
360       CopyMem(Info->Set+(StrSize(ArgSet)/sizeof(Info->Set[0])), gEfiShellParametersProtocol->Argv[1], NewSize);\r
361       Info->ReplacementName = Info->Set+StrSize(ArgSet)/sizeof(Info->Set[0]);\r
362       Info->CurrentValue  = (CHAR16*)Info->Set;\r
363       Info->Step          = 0;\r
364       Info->Current       = 0;\r
365       Info->End           = 0;\r
366 \r
367       if (InternalIsAliasOnList(Info->ReplacementName, &CurrentScriptFile->SubstList)) {\r
368         Info->RemoveSubstAlias  = FALSE;\r
369       } else {\r
370         Info->RemoveSubstAlias  = TRUE;\r
371       }\r
372       CurrentScriptFile->CurrentCommand->Data = Info;\r
373     } else if (gUnicodeCollation->StriColl(\r
374         gUnicodeCollation,\r
375         L"run",\r
376         gEfiShellParametersProtocol->Argv[2]) == 0) {\r
377       for (LoopVar = 0x3 ; LoopVar < gEfiShellParametersProtocol->Argc ; LoopVar++) {\r
378         ASSERT((ArgSet == NULL && ArgSize == 0) || (ArgSet != NULL));\r
379         if (ArgSet == NULL) {\r
380 //        ArgSet = StrnCatGrow(&ArgSet, &ArgSize, L"\"", 0);\r
381         } else {\r
382           ArgSet = StrnCatGrow(&ArgSet, &ArgSize, L"  ", 0);\r
383         }\r
384         ArgSet = StrnCatGrow(&ArgSet, &ArgSize, gEfiShellParametersProtocol->Argv[LoopVar], 0);\r
385 //        ArgSet = StrnCatGrow(&ArgSet, &ArgSize, L" ", 0);\r
386       }\r
387       //\r
388       // set up for a 'run' for loop\r
389       //\r
390       Info = AllocateZeroPool(sizeof(SHELL_FOR_INFO)+StrSize(gEfiShellParametersProtocol->Argv[1]));\r
391       ASSERT(Info != NULL);\r
392       CopyMem(Info->Set, gEfiShellParametersProtocol->Argv[1], StrSize(gEfiShellParametersProtocol->Argv[1]));\r
393       Info->ReplacementName = Info->Set;\r
394       Info->CurrentValue    = NULL;\r
395       ArgSetWalker            = ArgSet;\r
396       if (ArgSetWalker[0] != L'(') {\r
397         ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM_SCRIPT), gShellLevel1HiiHandle, ArgSet, ShellCommandGetCurrentScriptFile()->CurrentCommand->Line);\r
398         ShellStatus = SHELL_INVALID_PARAMETER;\r
399       } else {\r
400         ArgSetWalker++;\r
401         while (ArgSetWalker != NULL && ArgSetWalker[0] == L' ') {\r
402           ArgSetWalker++;\r
403         }\r
404         if (!ShellIsValidForNumber(ArgSetWalker)) {\r
405           ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM_SCRIPT), gShellLevel1HiiHandle, ArgSet, ShellCommandGetCurrentScriptFile()->CurrentCommand->Line);\r
406           ShellStatus = SHELL_INVALID_PARAMETER;\r
407         } else {\r
408           if (ArgSetWalker[0] == L'-') {\r
409             Info->Current = 0 - (INTN)ShellStrToUintn(ArgSetWalker+1);\r
410           } else {\r
411             Info->Current = (INTN)ShellStrToUintn(ArgSetWalker);\r
412           }\r
413           ArgSetWalker  = StrStr(ArgSetWalker, L" ");\r
414           while (ArgSetWalker != NULL && ArgSetWalker[0] == L' ') {\r
415             ArgSetWalker++;\r
416           }\r
417           if (ArgSetWalker == NULL || *ArgSetWalker == CHAR_NULL || !ShellIsValidForNumber(ArgSetWalker)){\r
418             ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM_SCRIPT), gShellLevel1HiiHandle, ArgSet, ShellCommandGetCurrentScriptFile()->CurrentCommand->Line);\r
419             ShellStatus = SHELL_INVALID_PARAMETER;\r
420           } else {\r
421             if (ArgSetWalker[0] == L'-') {\r
422               Info->End = 0 - (INTN)ShellStrToUintn(ArgSetWalker+1);\r
423             } else {\r
424               Info->End = (INTN)ShellStrToUintn(ArgSetWalker);\r
425             }\r
426             if (Info->Current < Info->End) {\r
427               Info->Step            = 1;\r
428             } else {\r
429               Info->Step            = -1;\r
430             }\r
431 \r
432             ArgSetWalker  = StrStr(ArgSetWalker, L" ");\r
433             while (ArgSetWalker != NULL && ArgSetWalker[0] == L' ') {\r
434               ArgSetWalker++;\r
435             }\r
436             if (ArgSetWalker != NULL && *ArgSetWalker != CHAR_NULL) {\r
437               TempSpot = StrStr(ArgSetWalker, L")");\r
438               if (TempSpot == NULL) {\r
439                 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM_SCRIPT), gShellLevel1HiiHandle, ArgSet, ShellCommandGetCurrentScriptFile()->CurrentCommand->Line);\r
440                 ShellStatus = SHELL_INVALID_PARAMETER;\r
441               } else {\r
442                 *TempSpot = CHAR_NULL;\r
443                 if (ArgSetWalker == NULL || *ArgSetWalker == CHAR_NULL || !ShellIsValidForNumber(ArgSetWalker)){\r
444                   ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM_SCRIPT), gShellLevel1HiiHandle, ArgSet, ShellCommandGetCurrentScriptFile()->CurrentCommand->Line);\r
445                   ShellStatus = SHELL_INVALID_PARAMETER;\r
446                 } else {\r
447                   if (*ArgSetWalker == L')') {\r
448                     ASSERT(Info->Step == 1 || Info->Step == -1);\r
449                   } else {\r
450                     if (ArgSetWalker[0] == L'-') {\r
451                       Info->Step = 0 - (INTN)ShellStrToUintn(ArgSetWalker+1);\r
452                     } else {\r
453                       Info->Step = (INTN)ShellStrToUintn(ArgSetWalker);\r
454                     }\r
455                   }\r
456                 }\r
457               }\r
458             }\r
459           }\r
460         }\r
461       }\r
462       if (ShellStatus == SHELL_SUCCESS) {\r
463         if (InternalIsAliasOnList(Info->ReplacementName, &CurrentScriptFile->SubstList)) {\r
464           Info->RemoveSubstAlias  = FALSE;\r
465         } else {\r
466           Info->RemoveSubstAlias  = TRUE;\r
467         }\r
468       }\r
469       CurrentScriptFile->CurrentCommand->Data = Info;\r
470     } else {\r
471       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM_SCRIPT), gShellLevel1HiiHandle, ArgSet, ShellCommandGetCurrentScriptFile()->CurrentCommand->Line);\r
472       ShellStatus = SHELL_INVALID_PARAMETER;\r
473     }\r
474   } else {\r
475     //\r
476     // These need to be NULL since they are used to determine if this is the first pass later on...\r
477     //\r
478     ASSERT(ArgSetWalker == NULL);\r
479     ASSERT(ArgSet       == NULL);\r
480   }\r
481 \r
482   Info = (SHELL_FOR_INFO*)CurrentScriptFile->CurrentCommand->Data;\r
483   if (CurrentScriptFile->CurrentCommand->Reset) {\r
484     Info->CurrentValue  = (CHAR16*)Info->Set;\r
485     FirstPass = TRUE;\r
486     CurrentScriptFile->CurrentCommand->Reset = FALSE;\r
487   }\r
488   if (ShellStatus == SHELL_SUCCESS) {\r
489     ASSERT(Info != NULL);\r
490     if (Info->Step != 0) {\r
491       //\r
492       // only advance if not the first pass\r
493       //\r
494       if (!FirstPass) {\r
495         //\r
496         // sequence version of for loop...\r
497         //\r
498         Info->Current += Info->Step;\r
499       }\r
500 \r
501       TempString = AllocateZeroPool(50*sizeof(CHAR16));\r
502       UnicodeSPrint(TempString, 50*sizeof(CHAR16), L"%d", Info->Current);\r
503       InternalUpdateAliasOnList(Info->ReplacementName, TempString, &CurrentScriptFile->SubstList);\r
504       FreePool(TempString);\r
505 \r
506       if ((Info->Step > 0 && Info->Current > Info->End) || (Info->Step < 0 && Info->Current < Info->End)) {\r
507         CurrentScriptFile->CurrentCommand->Data = NULL;\r
508         //\r
509         // find the matching endfor (we're done with the loop)\r
510         //\r
511         if (!MoveToTag(GetNextNode, L"endfor", L"for", NULL, CurrentScriptFile, TRUE, FALSE, FALSE)) {\r
512           ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_NO_MATCHING), gShellLevel1HiiHandle, L"EndFor", L"For", ShellCommandGetCurrentScriptFile()->CurrentCommand->Line);\r
513           ShellStatus = SHELL_DEVICE_ERROR;\r
514         }\r
515         if (Info->RemoveSubstAlias) {\r
516           //\r
517           // remove item from list\r
518           //\r
519           InternalRemoveAliasFromList(Info->ReplacementName, &CurrentScriptFile->SubstList);\r
520         }\r
521         FreePool(Info);\r
522       }\r
523     } else {\r
524       //\r
525       // Must be in 'in' version of for loop...\r
526       //\r
527       ASSERT(Info->Set != NULL);\r
528       if (Info->CurrentValue != NULL && *Info->CurrentValue != CHAR_NULL) {\r
529         if (Info->CurrentValue[0] == L'\"') {\r
530           Info->CurrentValue++;\r
531         }\r
532         while (Info->CurrentValue[0] == L' ') {\r
533           Info->CurrentValue++;\r
534         }\r
535         if (Info->CurrentValue[0] == L'\"') {\r
536           Info->CurrentValue++;\r
537         }\r
538         //\r
539         // do the next one of the set\r
540         //\r
541         ASSERT(TempString == NULL);\r
542         TempString = StrnCatGrow(&TempString, NULL, Info->CurrentValue, 0);\r
543         TempSpot   = StrStr(TempString, L"\" \"");\r
544         if (TempSpot != NULL) {\r
545           *TempSpot = CHAR_NULL;\r
546         }\r
547         while (TempString[StrLen(TempString)-1] == L'\"') {\r
548           TempString[StrLen(TempString)-1] = CHAR_NULL;\r
549         }\r
550         InternalUpdateAliasOnList(Info->ReplacementName, TempString, &CurrentScriptFile->SubstList);\r
551         Info->CurrentValue += StrLen(TempString);\r
552 \r
553         if (Info->CurrentValue[0] == L'\"') {\r
554           Info->CurrentValue++;\r
555         }\r
556         while (Info->CurrentValue[0] == L' ') {\r
557           Info->CurrentValue++;\r
558         }\r
559         if (Info->CurrentValue[0] == L'\"') {\r
560           Info->CurrentValue++;\r
561         }\r
562         FreePool(TempString);\r
563 \r
564       } else {\r
565         CurrentScriptFile->CurrentCommand->Data = NULL;\r
566         //\r
567         // find the matching endfor (we're done with the loop)\r
568         //\r
569         if (!MoveToTag(GetNextNode, L"endfor", L"for", NULL, CurrentScriptFile, TRUE, FALSE, FALSE)) {\r
570           ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_NO_MATCHING), gShellLevel1HiiHandle, L"EndFor", L"For", ShellCommandGetCurrentScriptFile()->CurrentCommand->Line);\r
571           ShellStatus = SHELL_DEVICE_ERROR;\r
572         }\r
573         if (Info->RemoveSubstAlias) {\r
574           //\r
575           // remove item from list\r
576           //\r
577           InternalRemoveAliasFromList(Info->ReplacementName, &CurrentScriptFile->SubstList);\r
578         }\r
579         FreePool(Info);\r
580       }\r
581     }\r
582   }\r
583   if (ArgSet != NULL) {\r
584     FreePool(ArgSet);\r
585   }\r
586   return (ShellStatus);\r
587 }\r
588 \r