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