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