Leaked source code of windows server 2003
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

/*++
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;
}