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 - 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
     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
     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
    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
    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
    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
    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
    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