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