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