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