You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
392 lines
12 KiB
392 lines
12 KiB
/*++
|
|
|
|
Copyright (c) 1999 Intel Corporation
|
|
|
|
Module Name:
|
|
|
|
for.c
|
|
|
|
Abstract:
|
|
|
|
Internal Shell cmd "for" & "endfor"
|
|
|
|
|
|
|
|
Revision History
|
|
|
|
--*/
|
|
|
|
#include "shelle.h"
|
|
|
|
|
|
/*
|
|
* Datatypes
|
|
*/
|
|
|
|
#define FOR_LOOP_INFO_SIGNATURE EFI_SIGNATURE_32('f','l','i','s')
|
|
typedef struct {
|
|
UINTN Signature;
|
|
LIST_ENTRY Link;
|
|
UINT64 LoopFilePos;
|
|
CHAR16 *IndexVarName;
|
|
LIST_ENTRY IndexValueList;
|
|
} FOR_LOOP_INFO;
|
|
|
|
#define FOR_LOOP_INDEXVAL_SIGNATURE EFI_SIGNATURE_32('f','l','v','s')
|
|
typedef struct {
|
|
UINTN Signature;
|
|
LIST_ENTRY Link;
|
|
CHAR16 *Value;
|
|
} FOR_LOOP_INDEXVAL;
|
|
|
|
/*
|
|
* Statics
|
|
*/
|
|
|
|
STATIC LIST_ENTRY ForLoopInfoStack;
|
|
STATIC UINTN NumActiveForLoops;
|
|
|
|
VOID
|
|
DumpForLoopInfoStack(VOID)
|
|
{
|
|
LIST_ENTRY *InfoLink;
|
|
LIST_ENTRY *IndexLink;
|
|
FOR_LOOP_INFO *LoopInfo;
|
|
FOR_LOOP_INDEXVAL *LoopIndexVal;
|
|
|
|
Print( L"FOR LOOP INFO STACK DUMP\n" );
|
|
for ( InfoLink = ForLoopInfoStack.Flink; InfoLink!=&ForLoopInfoStack; InfoLink=InfoLink->Flink) {
|
|
LoopInfo = CR(InfoLink, FOR_LOOP_INFO, Link, FOR_LOOP_INFO_SIGNATURE);
|
|
if ( LoopInfo ) {
|
|
Print( L" LoopFilePos 0x%X\n", LoopInfo->LoopFilePos );
|
|
Print( L" IndexVarName %s (0x%X)\n", LoopInfo->IndexVarName, LoopInfo->IndexVarName );
|
|
for ( IndexLink = LoopInfo->IndexValueList.Flink; IndexLink!=&LoopInfo->IndexValueList; IndexLink=IndexLink->Flink ) {
|
|
LoopIndexVal = CR(IndexLink, FOR_LOOP_INDEXVAL, Link, FOR_LOOP_INDEXVAL_SIGNATURE);
|
|
if ( LoopIndexVal ) {
|
|
if ( LoopIndexVal->Value ) {
|
|
Print( L" Loop index value %s\n", LoopIndexVal->Value );
|
|
} else {
|
|
Print( L" Loop index value is NULL\n" );
|
|
}
|
|
} else {
|
|
Print( L" Loop index value structure pointer is NULL\n" );
|
|
}
|
|
}
|
|
} else {
|
|
Print( L" LoopInfo NULL\n" );
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
/*///////////////////////////////////////////////////////////////////////
|
|
Function Name:
|
|
SEnvInitForLoopInfo
|
|
|
|
Description:
|
|
Initialize data structures used in or loop management.
|
|
*/
|
|
VOID
|
|
SEnvInitForLoopInfo (
|
|
VOID
|
|
)
|
|
{
|
|
InitializeListHead( &ForLoopInfoStack );
|
|
NumActiveForLoops = 0;
|
|
return;
|
|
}
|
|
|
|
/*///////////////////////////////////////////////////////////////////////
|
|
Function Name:
|
|
SEnvSubstituteForLoopIndex
|
|
|
|
Description:
|
|
Builtin shell command "for" for conditional execution in script files.
|
|
*/
|
|
EFI_STATUS
|
|
SEnvSubstituteForLoopIndex(
|
|
IN CHAR16 *Str,
|
|
OUT CHAR16 **Val
|
|
)
|
|
{
|
|
LIST_ENTRY *InfoLink = NULL;
|
|
LIST_ENTRY *IndexLink = NULL;
|
|
FOR_LOOP_INFO *LoopInfo = NULL;
|
|
FOR_LOOP_INDEXVAL *LoopIndexVal = NULL;
|
|
EFI_STATUS Status = EFI_SUCCESS;
|
|
|
|
/*
|
|
* Check if Str is a forloop index variable name on the forloop info stack
|
|
* If it is, return the current value
|
|
* Otherwise, just return the string.
|
|
*/
|
|
|
|
if ( Str[0] != L'%' || !IsWhiteSpace(Str[2]) ) {
|
|
Status = EFI_INVALID_PARAMETER;
|
|
goto Done;
|
|
}
|
|
|
|
/*
|
|
* We may have nested for loops, so we have to search through the variables for
|
|
* each for loop on the stack to see if we can match the variable name.
|
|
*/
|
|
for ( InfoLink = ForLoopInfoStack.Flink; InfoLink!=&ForLoopInfoStack; InfoLink=InfoLink->Flink) {
|
|
LoopInfo = CR(InfoLink, FOR_LOOP_INFO, Link, FOR_LOOP_INFO_SIGNATURE);
|
|
if ( LoopInfo ) {
|
|
if ( Str[1] == LoopInfo->IndexVarName[0] ) {
|
|
/* Found a match */
|
|
IndexLink = LoopInfo->IndexValueList.Flink;
|
|
LoopIndexVal = CR(IndexLink, FOR_LOOP_INDEXVAL, Link, FOR_LOOP_INDEXVAL_SIGNATURE);
|
|
if ( LoopIndexVal && LoopIndexVal->Value ) {
|
|
*Val = LoopIndexVal->Value;
|
|
Status = EFI_SUCCESS;
|
|
goto Done;
|
|
} else {
|
|
Status = EFI_INVALID_PARAMETER;
|
|
goto Done;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
*Val = NULL;
|
|
|
|
Done:
|
|
return Status;
|
|
}
|
|
|
|
|
|
/*///////////////////////////////////////////////////////////////////////
|
|
Function Name:
|
|
SEnvCmdFor
|
|
|
|
Description:
|
|
Builtin shell command "for" for conditional execution in script files.
|
|
*/
|
|
EFI_STATUS
|
|
SEnvCmdFor (
|
|
IN EFI_HANDLE ImageHandle,
|
|
IN EFI_SYSTEM_TABLE *SystemTable
|
|
)
|
|
{
|
|
CHAR16 **Argv;
|
|
UINTN Argc = 0;
|
|
UINTN Index = 0;
|
|
EFI_STATUS Status = EFI_SUCCESS;
|
|
UINTN i = 0;
|
|
LIST_ENTRY FileList;
|
|
LIST_ENTRY *Link = NULL;
|
|
SHELL_FILE_ARG *Arg = NULL;
|
|
FOR_LOOP_INFO *NewInfo = NULL;
|
|
FOR_LOOP_INDEXVAL *NewIndexVal = NULL;
|
|
|
|
InitializeShellApplication (ImageHandle, SystemTable);
|
|
Argv = SI->Argv;
|
|
Argc = SI->Argc;
|
|
|
|
InitializeListHead( &FileList );
|
|
|
|
if ( !SEnvBatchIsActive() ) {
|
|
Print( L"Error: FOR command only supported in script files\n" );
|
|
Status = EFI_UNSUPPORTED;
|
|
goto Done;
|
|
}
|
|
|
|
/*
|
|
* First, parse the command line arguments
|
|
*
|
|
* for %<var> in <string | file [[string | file]...]>
|
|
*/
|
|
|
|
if ( Argc < 4 ||
|
|
(StriCmp( Argv[2], L"in" ) != 0) ||
|
|
!(StrLen(Argv[1]) == 1 && IsAlpha(Argv[1][0]) ) )
|
|
{
|
|
Print( L"Argc %d, Argv[2] %s, StrLen(Argv[1]) %d, Argv[1][0] %c\n", Argc, Argv[2], StrLen(Argv[1]), Argv[1][0] );
|
|
Status = EFI_INVALID_PARAMETER;
|
|
goto Done;
|
|
}
|
|
|
|
/*
|
|
* Allocate a new forloop info structure for this for loop, and
|
|
* puch it on the for loop info stack.
|
|
*/
|
|
NewInfo = AllocateZeroPool( sizeof( FOR_LOOP_INFO ) );
|
|
if ( !NewInfo ) {
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
goto Done;
|
|
}
|
|
NewInfo->Signature = FOR_LOOP_INFO_SIGNATURE;
|
|
InsertHeadList( &ForLoopInfoStack, &NewInfo->Link );
|
|
|
|
/*
|
|
* Save the current script file position and the index variable name on
|
|
* the for-loop info stack. Increment the active-for-loop counter.
|
|
*/
|
|
SEnvBatchGetFilePos( &NewInfo->LoopFilePos );
|
|
InitializeListHead( &NewInfo->IndexValueList );
|
|
NumActiveForLoops++;
|
|
NewInfo->IndexVarName = StrDuplicate( Argv[1] );
|
|
|
|
/*
|
|
* Put the set of index values in the index value list for this for loop
|
|
*/
|
|
for ( i=3; i<Argc; i++ ) {
|
|
|
|
/*
|
|
* Expand any wildcard filename arguments
|
|
* Strings and non-wildcard filenames will accumulate in FileList
|
|
*/
|
|
|
|
Status = ShellFileMetaArg( Argv[i], &FileList);
|
|
if ( EFI_ERROR( Status ) ) {
|
|
Print( L"ShellFileMetaArg error: %r\n", Status );
|
|
}
|
|
|
|
/*
|
|
* Build the list of index values from the file list
|
|
* This will contain either the unexpanded argument or
|
|
* all the filenames matching an argument with wildcards
|
|
*/
|
|
|
|
for (Link=FileList.Flink; Link!=&FileList; Link=Link->Flink) {
|
|
Arg = CR(Link, SHELL_FILE_ARG, Link, SHELL_FILE_ARG_SIGNATURE);
|
|
|
|
NewIndexVal = AllocateZeroPool( sizeof(FOR_LOOP_INDEXVAL) );
|
|
if ( !NewIndexVal ) {
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
goto Done;
|
|
}
|
|
NewIndexVal->Signature = FOR_LOOP_INDEXVAL_SIGNATURE;
|
|
InsertTailList( &NewInfo->IndexValueList, &NewIndexVal->Link );
|
|
|
|
NewIndexVal->Value = AllocateZeroPool( StrSize(Arg->FileName) + sizeof(CHAR16) );
|
|
if ( !NewIndexVal->Value ) {
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
goto Done;
|
|
}
|
|
|
|
StrCpy( NewIndexVal->Value, Arg->FileName );
|
|
}
|
|
|
|
/*
|
|
* Free the file list that was allocated by ShellFileMetaArg
|
|
*/
|
|
ShellFreeFileList (&FileList);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Return control to the batch processing loop until an ENDFOR is encountered
|
|
*/
|
|
|
|
Done:
|
|
/*
|
|
* Free the file list
|
|
*/
|
|
if ( !IsListEmpty( &FileList ) ) {
|
|
ShellFreeFileList (&FileList);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
|
|
/*///////////////////////////////////////////////////////////////////////
|
|
Function Name:
|
|
SEnvCmdEndfor
|
|
|
|
Description:
|
|
Builtin shell command "endfor".
|
|
*/
|
|
EFI_STATUS
|
|
SEnvCmdEndfor (
|
|
IN EFI_HANDLE ImageHandle,
|
|
IN EFI_SYSTEM_TABLE *SystemTable
|
|
)
|
|
{
|
|
EFI_STATUS Status = EFI_SUCCESS;
|
|
LIST_ENTRY *InfoLink = NULL;
|
|
LIST_ENTRY *IndexLink = NULL;
|
|
FOR_LOOP_INFO *LoopInfo = NULL;
|
|
FOR_LOOP_INDEXVAL *LoopIndexVal = NULL;
|
|
|
|
InitializeShellApplication (ImageHandle, SystemTable);
|
|
|
|
if ( !SEnvBatchIsActive() ) {
|
|
Print( L"Error: ENDFOR command only supported in script files\n" );
|
|
Status = EFI_UNSUPPORTED;
|
|
goto Done;
|
|
}
|
|
|
|
if ( NumActiveForLoops == 0 ) {
|
|
Print( L"Error: ENDFOR with no corresponding FOR\n" );
|
|
Status = EFI_INVALID_PARAMETER;
|
|
goto Done;
|
|
}
|
|
|
|
/*
|
|
* Discard the index value for the just-completed iteration
|
|
*/
|
|
|
|
/* Get a pointer to the FOR_LOOP_INFO structure at the top of the stack (list) */
|
|
InfoLink = ForLoopInfoStack.Flink;
|
|
LoopInfo = CR(InfoLink, FOR_LOOP_INFO, Link, FOR_LOOP_INFO_SIGNATURE);
|
|
if ( LoopInfo ) {
|
|
|
|
/* Get a pointer to the FOR_LOOP_INDEXVAL structure at the front of the list */
|
|
IndexLink = LoopInfo->IndexValueList.Flink;
|
|
LoopIndexVal = CR(IndexLink, FOR_LOOP_INDEXVAL, Link, FOR_LOOP_INDEXVAL_SIGNATURE);
|
|
if ( LoopIndexVal ) {
|
|
|
|
/* Free the string containing the index value */
|
|
if ( LoopIndexVal->Value ) {
|
|
FreePool( LoopIndexVal->Value );
|
|
LoopIndexVal->Value = NULL;
|
|
}
|
|
|
|
/* Remove the used index value structure from the list and free it */
|
|
RemoveEntryList( &LoopIndexVal->Link );
|
|
FreePool( LoopIndexVal );
|
|
LoopIndexVal = NULL;
|
|
|
|
/*
|
|
* If there is another value, then jump back to top of loop,
|
|
* otherwise, exit this FOR loop & pop the FOR loop info stack.
|
|
*/
|
|
|
|
if ( !IsListEmpty( &LoopInfo->IndexValueList ) ) {
|
|
/*
|
|
* Set script file position back to top of this loop
|
|
*/
|
|
Status = SEnvBatchSetFilePos( LoopInfo->LoopFilePos );
|
|
if ( EFI_ERROR(Status) ) {
|
|
goto Done;
|
|
}
|
|
|
|
} else {
|
|
|
|
if ( LoopInfo->IndexVarName ) {
|
|
FreePool( LoopInfo->IndexVarName );
|
|
LoopInfo->IndexVarName = NULL;
|
|
}
|
|
|
|
/*
|
|
* Pop the stack and free the popped for loop info struct
|
|
*/
|
|
RemoveEntryList( &LoopInfo->Link );
|
|
if ( LoopInfo->IndexVarName ) {
|
|
FreePool( LoopInfo->IndexVarName );
|
|
}
|
|
FreePool( LoopInfo );
|
|
LoopInfo = NULL;
|
|
NumActiveForLoops--;
|
|
}
|
|
}
|
|
}
|
|
|
|
Done:
|
|
return EFI_SUCCESS;
|
|
}
|