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