Home | History | Annotate | Download | only in UefiShellLevel1CommandsLib
      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
     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
     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
    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
    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
    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
    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
    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