mirror of https://github.com/acidanthera/audk.git
1362 lines
37 KiB
C
1362 lines
37 KiB
C
/**@file
|
|
|
|
|
|
Copyright (c) 2006, Intel Corporation
|
|
All rights reserved. This program and the accompanying materials
|
|
are licensed and made available under the terms and conditions of the BSD License
|
|
which accompanies this distribution. The full text of the license may be found at
|
|
http://opensource.org/licenses/bsd-license.php
|
|
|
|
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|
|
|
**/
|
|
|
|
|
|
|
|
#include "Setup.h"
|
|
#include "Ui.h"
|
|
|
|
//
|
|
// Global stack used to evaluate boolean expresions
|
|
//
|
|
BOOLEAN *mBooleanEvaluationStack = (BOOLEAN) 0;
|
|
BOOLEAN *mBooleanEvaluationStackEnd = (BOOLEAN) 0;
|
|
|
|
STATIC
|
|
VOID
|
|
GrowBooleanStack (
|
|
IN OUT BOOLEAN **Stack,
|
|
IN UINTN StackSizeInBoolean
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Grow size of the boolean stack
|
|
|
|
Arguments:
|
|
|
|
Stack - Old stack on the way in and new stack on the way out
|
|
|
|
StackSizeInBoolean - New size of the stack
|
|
|
|
Returns:
|
|
|
|
NONE
|
|
|
|
--*/
|
|
{
|
|
BOOLEAN *NewStack;
|
|
|
|
NewStack = AllocatePool (StackSizeInBoolean * sizeof (BOOLEAN));
|
|
ASSERT (NewStack != NULL);
|
|
|
|
if (*Stack != NULL) {
|
|
//
|
|
// Copy to Old Stack to the New Stack
|
|
//
|
|
CopyMem (
|
|
NewStack,
|
|
mBooleanEvaluationStack,
|
|
(mBooleanEvaluationStackEnd - mBooleanEvaluationStack) * sizeof (BOOLEAN)
|
|
);
|
|
|
|
//
|
|
// Make the Stack pointer point to the old data in the new stack
|
|
//
|
|
*Stack = NewStack + (*Stack - mBooleanEvaluationStack);
|
|
|
|
//
|
|
// Free The Old Stack
|
|
//
|
|
FreePool (mBooleanEvaluationStack);
|
|
}
|
|
|
|
mBooleanEvaluationStack = NewStack;
|
|
mBooleanEvaluationStackEnd = NewStack + StackSizeInBoolean;
|
|
}
|
|
|
|
STATIC
|
|
VOID
|
|
InitializeBooleanEvaluator (
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Allocate a global stack for boolean processing.
|
|
|
|
Arguments:
|
|
|
|
NONE
|
|
|
|
Returns:
|
|
|
|
NONE
|
|
|
|
--*/
|
|
{
|
|
BOOLEAN *NullStack;
|
|
|
|
NullStack = NULL;
|
|
GrowBooleanStack (&NullStack, 0x1000);
|
|
}
|
|
|
|
STATIC
|
|
VOID
|
|
PushBool (
|
|
IN OUT BOOLEAN **Stack,
|
|
IN BOOLEAN BoolResult
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Push an element onto the Boolean Stack
|
|
|
|
Arguments:
|
|
|
|
Stack - Current stack location.
|
|
BoolResult - BOOLEAN to push.
|
|
|
|
Returns:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
CopyMem (*Stack, &BoolResult, sizeof (BOOLEAN));
|
|
*Stack += 1;
|
|
|
|
if (*Stack >= mBooleanEvaluationStackEnd) {
|
|
//
|
|
// If we run out of stack space make a new one that is 2X as big. Copy
|
|
// the old data into the new stack and update Stack to point to the old
|
|
// data in the new stack.
|
|
//
|
|
GrowBooleanStack (
|
|
Stack,
|
|
(mBooleanEvaluationStackEnd - mBooleanEvaluationStack) * sizeof (BOOLEAN) * 2
|
|
);
|
|
}
|
|
}
|
|
|
|
STATIC
|
|
BOOLEAN
|
|
PopBool (
|
|
IN OUT BOOLEAN **Stack
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Pop an element from the Boolean stack.
|
|
|
|
Arguments:
|
|
|
|
Stack - Current stack location
|
|
|
|
Returns:
|
|
|
|
Top of the BOOLEAN stack.
|
|
|
|
--*/
|
|
{
|
|
BOOLEAN ReturnValue;
|
|
|
|
*Stack -= 1;
|
|
CopyMem (&ReturnValue, *Stack, sizeof (BOOLEAN));
|
|
return ReturnValue;
|
|
}
|
|
|
|
STATIC
|
|
EFI_STATUS
|
|
GrowBooleanExpression (
|
|
IN EFI_INCONSISTENCY_DATA *InconsistentTags,
|
|
OUT VOID **BooleanExpression,
|
|
IN OUT UINTN *BooleanExpressionLength
|
|
)
|
|
{
|
|
UINT8 *NewExpression;
|
|
|
|
NewExpression = AllocatePool (*BooleanExpressionLength + sizeof (EFI_INCONSISTENCY_DATA));
|
|
ASSERT (NewExpression != NULL);
|
|
|
|
if (*BooleanExpression != NULL) {
|
|
//
|
|
// Copy Old buffer to the New buffer
|
|
//
|
|
CopyMem (NewExpression, *BooleanExpression, *BooleanExpressionLength);
|
|
|
|
CopyMem (&NewExpression[*BooleanExpressionLength], InconsistentTags, sizeof (EFI_INCONSISTENCY_DATA));
|
|
|
|
//
|
|
// Free The Old buffer
|
|
//
|
|
FreePool (*BooleanExpression);
|
|
} else {
|
|
//
|
|
// Copy data into new buffer
|
|
//
|
|
CopyMem (NewExpression, InconsistentTags, sizeof (EFI_INCONSISTENCY_DATA));
|
|
}
|
|
|
|
*BooleanExpressionLength = *BooleanExpressionLength + sizeof (EFI_INCONSISTENCY_DATA);
|
|
*BooleanExpression = (VOID *) NewExpression;
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
STATIC
|
|
VOID
|
|
CreateBooleanExpression (
|
|
IN EFI_FILE_FORM_TAGS *FileFormTags,
|
|
IN UINT16 Value,
|
|
IN UINT16 Id,
|
|
IN BOOLEAN Complex,
|
|
OUT VOID **BooleanExpression,
|
|
OUT UINTN *BooleanExpressionLength
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Returns:
|
|
|
|
--*/
|
|
{
|
|
UINTN Count;
|
|
EFI_INCONSISTENCY_DATA *InconsistentTags;
|
|
EFI_INCONSISTENCY_DATA FakeInconsistentTags;
|
|
|
|
InconsistentTags = FileFormTags->InconsistentTags;
|
|
|
|
//
|
|
// Did we run into a question that contains the Id we are looking for?
|
|
//
|
|
for (Count = 0; InconsistentTags->Operand != 0xFF; Count++) {
|
|
|
|
//
|
|
// Reserve INVALID_OFFSET_VALUE - 1 for TURE and FALSE, because we need to treat them as well
|
|
// as ideqid etc. but they have no coresponding id, so we reserve this value.
|
|
//
|
|
if (InconsistentTags->QuestionId1 == Id ||
|
|
InconsistentTags->QuestionId1 == INVALID_OFFSET_VALUE - 1) {
|
|
//
|
|
// If !Complex - means evaluate a single if/endif expression
|
|
//
|
|
if (!Complex) {
|
|
//
|
|
// If the ConsistencyId does not match the expression we are looking for
|
|
// skip to the next consistency database entry
|
|
//
|
|
if (InconsistentTags->ConsistencyId != Value) {
|
|
goto NextEntry;
|
|
}
|
|
}
|
|
//
|
|
// We need to rewind to the beginning of the Inconsistent expression
|
|
//
|
|
for (;
|
|
(InconsistentTags->Operand != FRAMEWORK_EFI_IFR_INCONSISTENT_IF_OP) &&
|
|
(InconsistentTags->Operand != FRAMEWORK_EFI_IFR_GRAYOUT_IF_OP) &&
|
|
(InconsistentTags->Operand != FRAMEWORK_EFI_IFR_SUPPRESS_IF_OP);
|
|
) {
|
|
InconsistentTags = InconsistentTags->Previous;
|
|
}
|
|
//
|
|
// Store the consistency check expression, ensure the next for loop starts at the op-code afterwards
|
|
//
|
|
GrowBooleanExpression (InconsistentTags, BooleanExpression, BooleanExpressionLength);
|
|
InconsistentTags = InconsistentTags->Next;
|
|
|
|
//
|
|
// Keep growing until we hit the End expression op-code or we hit the beginning of another
|
|
// consistency check like grayout/suppress
|
|
//
|
|
for (;
|
|
InconsistentTags->Operand != FRAMEWORK_EFI_IFR_END_IF_OP &&
|
|
InconsistentTags->Operand != FRAMEWORK_EFI_IFR_GRAYOUT_IF_OP &&
|
|
InconsistentTags->Operand != FRAMEWORK_EFI_IFR_SUPPRESS_IF_OP;
|
|
) {
|
|
GrowBooleanExpression (InconsistentTags, BooleanExpression, BooleanExpressionLength);
|
|
InconsistentTags = InconsistentTags->Next;
|
|
}
|
|
//
|
|
// Store the EndExpression Op-code
|
|
//
|
|
GrowBooleanExpression (InconsistentTags, BooleanExpression, BooleanExpressionLength);
|
|
}
|
|
|
|
NextEntry:
|
|
if (InconsistentTags->Next != NULL) {
|
|
//
|
|
// Skip to next entry
|
|
//
|
|
InconsistentTags = InconsistentTags->Next;
|
|
}
|
|
}
|
|
|
|
FakeInconsistentTags.Operand = 0;
|
|
|
|
//
|
|
// Add one last expression which will signify we have definitely hit the end
|
|
//
|
|
GrowBooleanExpression (&FakeInconsistentTags, BooleanExpression, BooleanExpressionLength);
|
|
}
|
|
|
|
STATIC
|
|
EFI_STATUS
|
|
BooleanVariableWorker (
|
|
IN CHAR16 *VariableName,
|
|
IN EFI_VARIABLE_DEFINITION *VariableDefinition,
|
|
IN BOOLEAN *StackPtr,
|
|
IN OUT UINTN *SizeOfVariable,
|
|
IN OUT VOID **VariableData
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
Returns:
|
|
|
|
--*/
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
Status = gRT->GetVariable (
|
|
VariableName,
|
|
&VariableDefinition->Guid,
|
|
NULL,
|
|
SizeOfVariable,
|
|
*VariableData
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
|
|
if (Status == EFI_BUFFER_TOO_SMALL) {
|
|
*VariableData = AllocatePool (*SizeOfVariable);
|
|
ASSERT (*VariableData != NULL);
|
|
|
|
Status = gRT->GetVariable (
|
|
VariableName,
|
|
&VariableDefinition->Guid,
|
|
NULL,
|
|
SizeOfVariable,
|
|
*VariableData
|
|
);
|
|
}
|
|
|
|
if (Status == EFI_NOT_FOUND) {
|
|
//
|
|
// This is a serious flaw, we must have some standard result if a variable
|
|
// is not found. Our default behavior must either be return a TRUE or FALSE
|
|
// since there is nothing else we can really do. Therefore, my crystal ball
|
|
// says I will return a FALSE
|
|
//
|
|
PushBool (&StackPtr, FALSE);
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
STATIC
|
|
UINT8
|
|
PredicateIfrType (
|
|
IN EFI_INCONSISTENCY_DATA *Iterator
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
This routine is for the purpose of predicate whether the Ifr is generated by a VfrCompiler greater than or equal to 1.88 or
|
|
less than 1.88 which is legacy.
|
|
|
|
Arguments:
|
|
Iterator - The pointer to inconsistency tags
|
|
|
|
Returns:
|
|
|
|
0x2 - If IFR is not legacy
|
|
|
|
0x1 - If IFR is legacy
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// legacy Ifr cover the states:
|
|
// Not ...
|
|
// Operand Opcode Operand
|
|
//
|
|
// while Operand means ideqval, TRUE, or other what can be evaluated to True or False,
|
|
// and Opcode means AND or OR.
|
|
//
|
|
if (Iterator->Operand == FRAMEWORK_EFI_IFR_NOT_OP ||
|
|
Iterator->Operand == 0) {
|
|
return 0x1;
|
|
} else if (Iterator->Operand == FRAMEWORK_EFI_IFR_EQ_VAR_VAL_OP ||
|
|
Iterator->Operand == FRAMEWORK_EFI_IFR_EQ_ID_VAL_OP ||
|
|
Iterator->Operand == FRAMEWORK_EFI_IFR_EQ_ID_ID_OP ||
|
|
Iterator->Operand == FRAMEWORK_EFI_IFR_EQ_ID_LIST_OP) {
|
|
Iterator++;
|
|
if (Iterator->Operand == FRAMEWORK_EFI_IFR_AND_OP ||
|
|
Iterator->Operand == FRAMEWORK_EFI_IFR_OR_OP) {
|
|
Iterator--;
|
|
return 0x1;
|
|
}
|
|
Iterator--;
|
|
}
|
|
return 0x2;
|
|
}
|
|
|
|
STATIC
|
|
VOID
|
|
PostOrderEvaluate (
|
|
IN EFI_FILE_FORM_TAGS *FileFormTags,
|
|
IN UINT16 Width,
|
|
IN OUT EFI_INCONSISTENCY_DATA **PIterator,
|
|
IN OUT BOOLEAN **StackPtr
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
PostOrderEvaluate is used for Ifr generated by VfrCompiler greater than or equal to 1.88,
|
|
which generate Operand Operand Opcode type Ifr.
|
|
PostOrderEvaluete only evaluate boolean expression part, not suppressif/grayoutif. TRUE,
|
|
FALSE, >=, >, (, ) are supported.
|
|
|
|
Arguments:
|
|
|
|
FileFormTags - The pointer to the tags of the form
|
|
|
|
Width - Width of Operand, recognized every iteration
|
|
|
|
PIterator - The pointer to inconsistency tags
|
|
|
|
StackPtr - The pointer to the evaluation stack
|
|
|
|
Returns:
|
|
|
|
TRUE - If value is valid
|
|
|
|
FALSE - If value is not valid
|
|
|
|
--*/
|
|
{
|
|
BOOLEAN Operator;
|
|
BOOLEAN Operator2;
|
|
UINT16 *MapBuffer;
|
|
UINT16 *MapBuffer2;
|
|
UINT16 MapValue;
|
|
UINT16 MapValue2;
|
|
UINTN SizeOfVariable;
|
|
CHAR16 VariableName[MAXIMUM_VALUE_CHARACTERS];
|
|
VOID *VariableData;
|
|
EFI_VARIABLE_DEFINITION *VariableDefinition;
|
|
EFI_STATUS Status;
|
|
UINTN Index;
|
|
BOOLEAN PushValue;
|
|
|
|
Operator = FALSE;
|
|
Operator2 = FALSE;
|
|
MapBuffer = NULL;
|
|
MapBuffer2 = NULL;
|
|
MapValue = 0;
|
|
MapValue2 = 0;
|
|
VariableData = NULL;
|
|
|
|
while (TRUE) {
|
|
if ((*PIterator)->Operand == 0) {
|
|
return;
|
|
}
|
|
|
|
Width = (*PIterator)->Width;
|
|
|
|
//
|
|
// Because INVALID_OFFSET_VALUE - 1 is reserved for TRUE or FALSE, omit them.
|
|
//
|
|
if ((*PIterator)->QuestionId1 != INVALID_OFFSET_VALUE &&
|
|
(*PIterator)->QuestionId1 != INVALID_OFFSET_VALUE - 1) {
|
|
ExtractNvValue (FileFormTags, (*PIterator)->VariableNumber, Width, (*PIterator)->QuestionId1, (VOID **) &MapBuffer);
|
|
ExtractNvValue (FileFormTags, (*PIterator)->VariableNumber2, Width, (*PIterator)->QuestionId2, (VOID **) &MapBuffer2);
|
|
if (MapBuffer != NULL) {
|
|
if (Width == 2) {
|
|
MapValue = *MapBuffer;
|
|
} else {
|
|
MapValue = (UINT8) *MapBuffer;
|
|
}
|
|
|
|
FreePool (MapBuffer);
|
|
}
|
|
|
|
if (MapBuffer2 != NULL) {
|
|
if (Width == 2) {
|
|
MapValue2 = *MapBuffer2;
|
|
} else {
|
|
MapValue2 = (UINT8) *MapBuffer2;
|
|
}
|
|
|
|
FreePool (MapBuffer2);
|
|
}
|
|
}
|
|
|
|
switch ((*PIterator)->Operand) {
|
|
case FRAMEWORK_EFI_IFR_EQ_VAR_VAL_OP:
|
|
UnicodeValueToString (
|
|
VariableName,
|
|
FALSE,
|
|
(UINTN) (*PIterator)->QuestionId1,
|
|
(sizeof (VariableName) / sizeof (VariableName[0])) - 1
|
|
);
|
|
|
|
SizeOfVariable = 0;
|
|
|
|
ExtractRequestedNvMap (FileFormTags, (*PIterator)->VariableNumber, &VariableDefinition);
|
|
|
|
Status = BooleanVariableWorker (
|
|
VariableName,
|
|
VariableDefinition,
|
|
*StackPtr,
|
|
&SizeOfVariable,
|
|
&VariableData
|
|
);
|
|
|
|
if (!EFI_ERROR (Status)) {
|
|
if (SizeOfVariable == 1) {
|
|
CopyMem (&MapValue, VariableData, 1);
|
|
} else {
|
|
CopyMem (&MapValue, VariableData, 2);
|
|
}
|
|
|
|
//
|
|
// Do operation after knowing the compare operator.
|
|
//
|
|
MapValue2 = (*PIterator)->Value;
|
|
(*PIterator)++;
|
|
if ((*PIterator)->Operand == FRAMEWORK_EFI_IFR_GT_OP) {
|
|
PushValue = (BOOLEAN) (MapValue > MapValue2);
|
|
} else if ((*PIterator)->Operand == FRAMEWORK_EFI_IFR_GE_OP) {
|
|
PushValue = (BOOLEAN) (MapValue >= MapValue2);
|
|
} else {
|
|
(*PIterator)--;
|
|
PushValue = (BOOLEAN) (MapValue == MapValue2);
|
|
}
|
|
PushBool (StackPtr, PushValue);
|
|
}
|
|
|
|
break;
|
|
|
|
case FRAMEWORK_EFI_IFR_EQ_ID_VAL_OP:
|
|
//
|
|
// Do operation after knowing the compare operator.
|
|
//
|
|
MapValue2 = (*PIterator)->Value;
|
|
(*PIterator)++;
|
|
if ((*PIterator)->Operand == FRAMEWORK_EFI_IFR_GT_OP) {
|
|
PushValue = (BOOLEAN) (MapValue > MapValue2);
|
|
} else if ((*PIterator)->Operand == FRAMEWORK_EFI_IFR_GE_OP) {
|
|
PushValue = (BOOLEAN) (MapValue >= MapValue2);
|
|
} else {
|
|
(*PIterator)--;
|
|
PushValue = (BOOLEAN) (MapValue == MapValue2);
|
|
}
|
|
PushBool (StackPtr, PushValue);
|
|
break;
|
|
|
|
case FRAMEWORK_EFI_IFR_EQ_ID_ID_OP:
|
|
//
|
|
// Do operation after knowing the compare operator.
|
|
//
|
|
(*PIterator)++;
|
|
if ((*PIterator)->Operand == FRAMEWORK_EFI_IFR_GT_OP) {
|
|
PushValue = (BOOLEAN) (MapValue > MapValue2);
|
|
} else if ((*PIterator)->Operand == FRAMEWORK_EFI_IFR_GE_OP) {
|
|
PushValue = (BOOLEAN) (MapValue >= MapValue2);
|
|
} else {
|
|
(*PIterator)--;
|
|
PushValue = (BOOLEAN) (MapValue == MapValue2);
|
|
}
|
|
PushBool (StackPtr, PushValue);
|
|
break;
|
|
|
|
case FRAMEWORK_EFI_IFR_EQ_ID_LIST_OP:
|
|
for (Index = 0; Index < (*PIterator)->ListLength; Index++) {
|
|
Operator = (BOOLEAN) (MapValue == (*PIterator)->ValueList[Index]);
|
|
if (Operator) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
PushBool (StackPtr, Operator);
|
|
break;
|
|
|
|
case FRAMEWORK_EFI_IFR_TRUE_OP:
|
|
PushBool (StackPtr, TRUE);
|
|
break;
|
|
|
|
case FRAMEWORK_EFI_IFR_FALSE_OP:
|
|
PushBool (StackPtr, FALSE);
|
|
break;
|
|
|
|
case FRAMEWORK_EFI_IFR_AND_OP:
|
|
Operator = PopBool (StackPtr);
|
|
Operator2 = PopBool (StackPtr);
|
|
PushBool (StackPtr, (BOOLEAN) (Operator && Operator2));
|
|
break;
|
|
case FRAMEWORK_EFI_IFR_OR_OP:
|
|
Operator = PopBool (StackPtr);
|
|
Operator2 = PopBool (StackPtr);
|
|
PushBool (StackPtr, (BOOLEAN) (Operator || Operator2));
|
|
break;
|
|
case FRAMEWORK_EFI_IFR_NOT_OP:
|
|
Operator = PopBool (StackPtr);
|
|
PushBool (StackPtr, (BOOLEAN) (!Operator));
|
|
break;
|
|
|
|
case FRAMEWORK_EFI_IFR_SUPPRESS_IF_OP:
|
|
case FRAMEWORK_EFI_IFR_GRAYOUT_IF_OP:
|
|
case FRAMEWORK_EFI_IFR_INCONSISTENT_IF_OP:
|
|
default:
|
|
//
|
|
// Return to the previous tag if runs out of boolean expression.
|
|
//
|
|
(*PIterator)--;
|
|
return;
|
|
}
|
|
(*PIterator)++;
|
|
}
|
|
}
|
|
|
|
BOOLEAN
|
|
ValueIsNotValid (
|
|
IN BOOLEAN Complex,
|
|
IN UINT16 Value,
|
|
IN EFI_TAG *Tag,
|
|
IN EFI_FILE_FORM_TAGS *FileFormTags,
|
|
IN STRING_REF *PopUp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
Returns:
|
|
|
|
TRUE - If value is valid
|
|
|
|
FALSE - If value is not valid
|
|
|
|
--*/
|
|
{
|
|
BOOLEAN *StackPtr;
|
|
EFI_INCONSISTENCY_DATA *Iterator;
|
|
BOOLEAN Operator;
|
|
BOOLEAN Operator2;
|
|
UINTN Index;
|
|
VOID *BooleanExpression;
|
|
UINTN BooleanExpressionLength;
|
|
BOOLEAN NotOperator;
|
|
BOOLEAN OrOperator;
|
|
BOOLEAN AndOperator;
|
|
BOOLEAN ArtificialEnd;
|
|
UINT16 *MapBuffer;
|
|
UINT16 *MapBuffer2;
|
|
UINT16 MapValue;
|
|
UINT16 MapValue2;
|
|
UINTN SizeOfVariable;
|
|
CHAR16 VariableName[MAXIMUM_VALUE_CHARACTERS];
|
|
VOID *VariableData;
|
|
EFI_STATUS Status;
|
|
UINT16 Id;
|
|
UINT16 Width;
|
|
EFI_VARIABLE_DEFINITION *VariableDefinition;
|
|
BOOLEAN CosmeticConsistency;
|
|
UINT8 IsLegacy;
|
|
|
|
VariableData = NULL;
|
|
BooleanExpressionLength = 0;
|
|
BooleanExpression = NULL;
|
|
Operator = FALSE;
|
|
ArtificialEnd = FALSE;
|
|
CosmeticConsistency = TRUE;
|
|
IsLegacy = 0;
|
|
|
|
Id = Tag->Id;
|
|
if (Tag->StorageWidth == 1) {
|
|
Width = 1;
|
|
} else {
|
|
Width = 2;
|
|
}
|
|
CreateBooleanExpression (FileFormTags, Value, Id, Complex, &BooleanExpression, &BooleanExpressionLength);
|
|
|
|
if (mBooleanEvaluationStack == 0) {
|
|
InitializeBooleanEvaluator ();
|
|
}
|
|
|
|
if (BooleanExpression == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
StackPtr = mBooleanEvaluationStack;
|
|
Iterator = BooleanExpression;
|
|
MapBuffer = NULL;
|
|
MapBuffer2 = NULL;
|
|
MapValue = 0;
|
|
MapValue2 = 0;
|
|
|
|
while (TRUE) {
|
|
NotOperator = FALSE;
|
|
OrOperator = FALSE;
|
|
AndOperator = FALSE;
|
|
|
|
if (Iterator->Operand == 0) {
|
|
return Operator;
|
|
}
|
|
|
|
//
|
|
// Because INVALID_OFFSET_VALUE - 1 is reserved for TRUE or FALSE, omit them.
|
|
//
|
|
if (Iterator->QuestionId1 != INVALID_OFFSET_VALUE &&
|
|
Iterator->QuestionId1 != INVALID_OFFSET_VALUE-1) {
|
|
ExtractNvValue (FileFormTags, Iterator->VariableNumber, Width, Iterator->QuestionId1, (VOID **) &MapBuffer);
|
|
ExtractNvValue (FileFormTags, Iterator->VariableNumber2, Width, Iterator->QuestionId2, (VOID **) &MapBuffer2);
|
|
if (MapBuffer != NULL) {
|
|
if (Width == 2) {
|
|
MapValue = *MapBuffer;
|
|
} else {
|
|
MapValue = (UINT8) *MapBuffer;
|
|
}
|
|
|
|
FreePool (MapBuffer);
|
|
}
|
|
|
|
if (MapBuffer2 != NULL) {
|
|
if (Width == 2) {
|
|
MapValue2 = *MapBuffer2;
|
|
} else {
|
|
MapValue2 = (UINT8) *MapBuffer2;
|
|
}
|
|
|
|
FreePool (MapBuffer2);
|
|
}
|
|
}
|
|
|
|
switch (Iterator->Operand) {
|
|
case FRAMEWORK_EFI_IFR_SUPPRESS_IF_OP:
|
|
//
|
|
// Must have hit a suppress followed by a grayout or vice-versa
|
|
//
|
|
if (ArtificialEnd) {
|
|
ArtificialEnd = FALSE;
|
|
Operator = PopBool (&StackPtr);
|
|
if (Operator) {
|
|
Tag->Suppress = TRUE;
|
|
}
|
|
|
|
return Operator;
|
|
}
|
|
|
|
ArtificialEnd = TRUE;
|
|
*PopUp = Iterator->Popup;
|
|
break;
|
|
|
|
case FRAMEWORK_EFI_IFR_GRAYOUT_IF_OP:
|
|
//
|
|
// Must have hit a suppress followed by a grayout or vice-versa
|
|
//
|
|
if (ArtificialEnd) {
|
|
ArtificialEnd = FALSE;
|
|
Operator = PopBool (&StackPtr);
|
|
if (Operator) {
|
|
Tag->GrayOut = TRUE;
|
|
}
|
|
|
|
return Operator;
|
|
}
|
|
|
|
ArtificialEnd = TRUE;
|
|
*PopUp = Iterator->Popup;
|
|
break;
|
|
|
|
case FRAMEWORK_EFI_IFR_INCONSISTENT_IF_OP:
|
|
CosmeticConsistency = FALSE;
|
|
*PopUp = Iterator->Popup;
|
|
break;
|
|
|
|
//
|
|
// In the case of external variable values, we must read the variable which is
|
|
// named by the human readable version of the OpCode->VariableId and the guid of the formset
|
|
//
|
|
case FRAMEWORK_EFI_IFR_EQ_VAR_VAL_OP:
|
|
//
|
|
// To check whether Ifr is legacy. Once every boolean expression.
|
|
//
|
|
if (IsLegacy == 0) {
|
|
IsLegacy = PredicateIfrType (Iterator);
|
|
}
|
|
if (IsLegacy == 0x2) {
|
|
PostOrderEvaluate (FileFormTags, Width, &Iterator, &StackPtr);
|
|
break;
|
|
}
|
|
|
|
UnicodeValueToString (
|
|
VariableName,
|
|
FALSE,
|
|
(UINTN) Iterator->QuestionId1,
|
|
(sizeof (VariableName) / sizeof (VariableName[0])) - 1
|
|
);
|
|
|
|
SizeOfVariable = 0;
|
|
|
|
ExtractRequestedNvMap (FileFormTags, Iterator->VariableNumber, &VariableDefinition);
|
|
|
|
Status = BooleanVariableWorker (
|
|
VariableName,
|
|
VariableDefinition,
|
|
StackPtr,
|
|
&SizeOfVariable,
|
|
&VariableData
|
|
);
|
|
|
|
if (!EFI_ERROR (Status)) {
|
|
if (SizeOfVariable == 1) {
|
|
CopyMem (&MapValue, VariableData, 1);
|
|
} else {
|
|
CopyMem (&MapValue, VariableData, 2);
|
|
}
|
|
|
|
PushBool (&StackPtr, (BOOLEAN) (MapValue == Iterator->Value));
|
|
}
|
|
|
|
break;
|
|
|
|
case FRAMEWORK_EFI_IFR_EQ_ID_VAL_OP:
|
|
//
|
|
// To check whether Ifr is legacy. Once every boolean expression.
|
|
//
|
|
if (IsLegacy == 0) {
|
|
IsLegacy = PredicateIfrType (Iterator);
|
|
}
|
|
if (IsLegacy == 0x2) {
|
|
PostOrderEvaluate (FileFormTags, Width, &Iterator, &StackPtr);
|
|
break;
|
|
}
|
|
|
|
PushBool (&StackPtr, (BOOLEAN) (MapValue == Iterator->Value));
|
|
break;
|
|
|
|
case FRAMEWORK_EFI_IFR_EQ_ID_ID_OP:
|
|
//
|
|
// To check whether Ifr is legacy. Once every boolean expression.
|
|
//
|
|
if (IsLegacy == 0) {
|
|
IsLegacy = PredicateIfrType (Iterator);
|
|
}
|
|
if (IsLegacy == 0x2) {
|
|
PostOrderEvaluate (FileFormTags, Width, &Iterator, &StackPtr);
|
|
break;
|
|
}
|
|
|
|
PushBool (&StackPtr, (BOOLEAN) (MapValue == MapValue2));
|
|
break;
|
|
|
|
case FRAMEWORK_EFI_IFR_EQ_ID_LIST_OP:
|
|
//
|
|
// To check whether Ifr is legacy. Once every boolean expression.
|
|
//
|
|
if (IsLegacy == 0) {
|
|
IsLegacy = PredicateIfrType (Iterator);
|
|
}
|
|
if (IsLegacy == 0x2) {
|
|
PostOrderEvaluate (FileFormTags, Width, &Iterator, &StackPtr);
|
|
break;
|
|
}
|
|
|
|
for (Index = 0; Index < Iterator->ListLength; Index++) {
|
|
Operator = (BOOLEAN) (MapValue == Iterator->ValueList[Index]);
|
|
if (Operator) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
PushBool (&StackPtr, Operator);
|
|
break;
|
|
|
|
case FRAMEWORK_EFI_IFR_AND_OP:
|
|
Iterator++;
|
|
if (Iterator->Operand == FRAMEWORK_EFI_IFR_NOT_OP) {
|
|
NotOperator = TRUE;
|
|
Iterator++;
|
|
}
|
|
|
|
if (Iterator->QuestionId1 != INVALID_OFFSET_VALUE) {
|
|
ExtractNvValue (FileFormTags, Iterator->VariableNumber, Width, Iterator->QuestionId1, (VOID **) &MapBuffer);
|
|
ExtractNvValue (FileFormTags, Iterator->VariableNumber2, Width, Iterator->QuestionId2, (VOID **) &MapBuffer2);
|
|
if (MapBuffer != NULL) {
|
|
if (Width == 2) {
|
|
MapValue = *MapBuffer;
|
|
} else {
|
|
MapValue = (UINT8) *MapBuffer;
|
|
}
|
|
|
|
FreePool (MapBuffer);
|
|
}
|
|
|
|
if (MapBuffer2 != NULL) {
|
|
if (Width == 2) {
|
|
MapValue2 = *MapBuffer2;
|
|
} else {
|
|
MapValue2 = (UINT8) *MapBuffer2;
|
|
}
|
|
|
|
FreePool (MapBuffer2);
|
|
}
|
|
}
|
|
|
|
switch (Iterator->Operand) {
|
|
case FRAMEWORK_EFI_IFR_EQ_ID_VAL_OP:
|
|
//
|
|
// If Not - flip the results
|
|
//
|
|
if (NotOperator) {
|
|
Operator = (BOOLEAN)!(MapValue == Iterator->Value);
|
|
} else {
|
|
Operator = (BOOLEAN) (MapValue == Iterator->Value);
|
|
}
|
|
|
|
PushBool (&StackPtr, Operator);
|
|
break;
|
|
|
|
//
|
|
// In the case of external variable values, we must read the variable which is
|
|
// named by the human readable version of the OpCode->VariableId and the guid of the formset
|
|
//
|
|
case FRAMEWORK_EFI_IFR_EQ_VAR_VAL_OP:
|
|
UnicodeValueToString (
|
|
VariableName,
|
|
FALSE,
|
|
(UINTN) Iterator->QuestionId1,
|
|
(sizeof (VariableName) / sizeof (VariableName[0])) - 1
|
|
);
|
|
|
|
SizeOfVariable = 0;
|
|
|
|
ExtractRequestedNvMap (FileFormTags, Iterator->VariableNumber, &VariableDefinition);
|
|
|
|
Status = BooleanVariableWorker (
|
|
VariableName,
|
|
VariableDefinition,
|
|
StackPtr,
|
|
&SizeOfVariable,
|
|
&VariableData
|
|
);
|
|
|
|
if (!EFI_ERROR (Status)) {
|
|
if (SizeOfVariable == 1) {
|
|
CopyMem (&MapValue, VariableData, 1);
|
|
} else {
|
|
CopyMem (&MapValue, VariableData, 2);
|
|
}
|
|
//
|
|
// If Not - flip the results
|
|
//
|
|
if (NotOperator) {
|
|
PushBool (&StackPtr, (BOOLEAN)!(MapValue == Iterator->Value));
|
|
} else {
|
|
PushBool (&StackPtr, (BOOLEAN) (MapValue == Iterator->Value));
|
|
}
|
|
}
|
|
break;
|
|
|
|
case FRAMEWORK_EFI_IFR_EQ_ID_ID_OP:
|
|
//
|
|
// If Not - flip the results
|
|
//
|
|
if (NotOperator) {
|
|
Operator = (BOOLEAN)!(MapValue == MapValue2);
|
|
} else {
|
|
Operator = (BOOLEAN) (MapValue == MapValue2);
|
|
}
|
|
|
|
PushBool (&StackPtr, Operator);
|
|
break;
|
|
|
|
case FRAMEWORK_EFI_IFR_EQ_ID_LIST_OP:
|
|
for (Index = 0; Index < Iterator->ListLength; Index++) {
|
|
//
|
|
// If Not - flip the results
|
|
//
|
|
if (NotOperator) {
|
|
Operator = (BOOLEAN)!(MapValue == Iterator->ValueList[Index]);
|
|
} else {
|
|
Operator = (BOOLEAN) (MapValue == Iterator->ValueList[Index]);
|
|
}
|
|
//
|
|
// If We are trying to make sure that MapValue != Item[x], keep looking through
|
|
// the list to make sure we don't equal any other items
|
|
//
|
|
if (Operator && NotOperator) {
|
|
continue;
|
|
}
|
|
//
|
|
// If MapValue == Item, then we have succeeded (first found is good enough)
|
|
//
|
|
if (Operator) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
PushBool (&StackPtr, Operator);
|
|
break;
|
|
|
|
default:
|
|
return FALSE;
|
|
}
|
|
|
|
Operator = PopBool (&StackPtr);
|
|
Operator2 = PopBool (&StackPtr);
|
|
PushBool (&StackPtr, (BOOLEAN) (Operator && Operator2));
|
|
break;
|
|
|
|
case FRAMEWORK_EFI_IFR_OR_OP:
|
|
Iterator++;
|
|
if (Iterator->Operand == FRAMEWORK_EFI_IFR_NOT_OP) {
|
|
NotOperator = TRUE;
|
|
Iterator++;
|
|
}
|
|
|
|
if (Iterator->QuestionId1 != INVALID_OFFSET_VALUE) {
|
|
ExtractNvValue (FileFormTags, Iterator->VariableNumber, Width, Iterator->QuestionId1, (VOID **) &MapBuffer);
|
|
ExtractNvValue (FileFormTags, Iterator->VariableNumber2, Width, Iterator->QuestionId2, (VOID **) &MapBuffer2);
|
|
if (MapBuffer != NULL) {
|
|
if (Width == 2) {
|
|
MapValue = *MapBuffer;
|
|
} else {
|
|
MapValue = (UINT8) *MapBuffer;
|
|
}
|
|
|
|
FreePool (MapBuffer);
|
|
}
|
|
|
|
if (MapBuffer2 != NULL) {
|
|
if (Width == 2) {
|
|
MapValue2 = *MapBuffer2;
|
|
} else {
|
|
MapValue2 = (UINT8) *MapBuffer2;
|
|
}
|
|
|
|
FreePool (MapBuffer2);
|
|
}
|
|
}
|
|
|
|
switch (Iterator->Operand) {
|
|
case FRAMEWORK_EFI_IFR_EQ_ID_VAL_OP:
|
|
//
|
|
// If Not - flip the results
|
|
//
|
|
if (NotOperator) {
|
|
Operator = (BOOLEAN)!(MapValue == Iterator->Value);
|
|
} else {
|
|
Operator = (BOOLEAN) (MapValue == Iterator->Value);
|
|
}
|
|
|
|
PushBool (&StackPtr, Operator);
|
|
break;
|
|
|
|
//
|
|
// In the case of external variable values, we must read the variable which is
|
|
// named by the human readable version of the OpCode->VariableId and the guid of the formset
|
|
//
|
|
case FRAMEWORK_EFI_IFR_EQ_VAR_VAL_OP:
|
|
UnicodeValueToString (
|
|
VariableName,
|
|
FALSE,
|
|
(UINTN) Iterator->QuestionId1,
|
|
(sizeof (VariableName) / sizeof (VariableName[0])) - 1
|
|
);
|
|
|
|
SizeOfVariable = 0;
|
|
|
|
ExtractRequestedNvMap (FileFormTags, Iterator->VariableNumber, &VariableDefinition);
|
|
|
|
Status = BooleanVariableWorker (
|
|
VariableName,
|
|
VariableDefinition,
|
|
StackPtr,
|
|
&SizeOfVariable,
|
|
&VariableData
|
|
);
|
|
|
|
if (!EFI_ERROR (Status)) {
|
|
if (SizeOfVariable == 1) {
|
|
CopyMem (&MapValue, VariableData, 1);
|
|
} else {
|
|
CopyMem (&MapValue, VariableData, 2);
|
|
}
|
|
//
|
|
// If Not - flip the results
|
|
//
|
|
if (NotOperator) {
|
|
PushBool (&StackPtr, (BOOLEAN)!(MapValue == Iterator->Value));
|
|
} else {
|
|
PushBool (&StackPtr, (BOOLEAN) (MapValue == Iterator->Value));
|
|
}
|
|
}
|
|
break;
|
|
|
|
case FRAMEWORK_EFI_IFR_EQ_ID_ID_OP:
|
|
//
|
|
// If Not - flip the results
|
|
//
|
|
if (NotOperator) {
|
|
Operator = (BOOLEAN)!(MapValue == MapValue2);
|
|
} else {
|
|
Operator = (BOOLEAN) (MapValue == MapValue2);
|
|
}
|
|
|
|
PushBool (&StackPtr, Operator);
|
|
break;
|
|
|
|
case FRAMEWORK_EFI_IFR_EQ_ID_LIST_OP:
|
|
for (Index = 0; Index < Iterator->ListLength; Index++) {
|
|
//
|
|
// If Not - flip the results
|
|
//
|
|
if (NotOperator) {
|
|
Operator = (BOOLEAN)!(MapValue == Iterator->ValueList[Index]);
|
|
} else {
|
|
Operator = (BOOLEAN) (MapValue == Iterator->ValueList[Index]);
|
|
}
|
|
//
|
|
// If We are trying to make sure that MapValue != Item[x], keep looking through
|
|
// the list to make sure we don't equal any other items
|
|
//
|
|
if (Operator && NotOperator) {
|
|
continue;
|
|
}
|
|
//
|
|
// If MapValue == Item, then we have succeeded (first found is good enough)
|
|
//
|
|
if (Operator) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
PushBool (&StackPtr, Operator);
|
|
break;
|
|
|
|
default:
|
|
return FALSE;
|
|
}
|
|
|
|
Operator = PopBool (&StackPtr);
|
|
Operator2 = PopBool (&StackPtr);
|
|
PushBool (&StackPtr, (BOOLEAN) (Operator || Operator2));
|
|
break;
|
|
|
|
case FRAMEWORK_EFI_IFR_NOT_OP:
|
|
//
|
|
// To check whether Ifr is legacy. Once every boolean expression.
|
|
//
|
|
if (IsLegacy == 0) {
|
|
IsLegacy = PredicateIfrType (Iterator);
|
|
}
|
|
if (IsLegacy == 0x2) {
|
|
PostOrderEvaluate (FileFormTags, Width, &Iterator, &StackPtr);
|
|
break;
|
|
}
|
|
|
|
//
|
|
// I don't need to set the NotOperator (I know that I have to NOT this in this case
|
|
//
|
|
Iterator++;
|
|
|
|
if (Iterator->Operand == FRAMEWORK_EFI_IFR_OR_OP) {
|
|
OrOperator = TRUE;
|
|
Iterator++;
|
|
}
|
|
|
|
if (Iterator->Operand == FRAMEWORK_EFI_IFR_AND_OP) {
|
|
AndOperator = TRUE;
|
|
Iterator++;
|
|
}
|
|
|
|
if (Iterator->QuestionId1 != INVALID_OFFSET_VALUE) {
|
|
ExtractNvValue (FileFormTags, Iterator->VariableNumber, Width, Iterator->QuestionId1, (VOID **) &MapBuffer);
|
|
ExtractNvValue (FileFormTags, Iterator->VariableNumber2, Width, Iterator->QuestionId2, (VOID **) &MapBuffer2);
|
|
if (MapBuffer != NULL) {
|
|
if (Width == 2) {
|
|
MapValue = *MapBuffer;
|
|
} else {
|
|
MapValue = (UINT8) *MapBuffer;
|
|
}
|
|
|
|
FreePool (MapBuffer);
|
|
}
|
|
|
|
if (MapBuffer2 != NULL) {
|
|
if (Width == 2) {
|
|
MapValue2 = *MapBuffer2;
|
|
} else {
|
|
MapValue2 = (UINT8) *MapBuffer2;
|
|
}
|
|
|
|
FreePool (MapBuffer2);
|
|
}
|
|
}
|
|
|
|
switch (Iterator->Operand) {
|
|
case FRAMEWORK_EFI_IFR_EQ_ID_VAL_OP:
|
|
Operator = (BOOLEAN)!(MapValue == Iterator->Value);
|
|
PushBool (&StackPtr, Operator);
|
|
break;
|
|
|
|
//
|
|
// In the case of external variable values, we must read the variable which is
|
|
// named by the human readable version of the OpCode->VariableId and the guid of the formset
|
|
//
|
|
case FRAMEWORK_EFI_IFR_EQ_VAR_VAL_OP:
|
|
UnicodeValueToString (
|
|
VariableName,
|
|
FALSE,
|
|
(UINTN) Iterator->QuestionId1,
|
|
(sizeof (VariableName) / sizeof (VariableName[0])) - 1
|
|
);
|
|
|
|
SizeOfVariable = 0;
|
|
|
|
ExtractRequestedNvMap (FileFormTags, Iterator->VariableNumber, &VariableDefinition);
|
|
|
|
Status = BooleanVariableWorker (
|
|
VariableName,
|
|
VariableDefinition,
|
|
StackPtr,
|
|
&SizeOfVariable,
|
|
&VariableData
|
|
);
|
|
|
|
if (!EFI_ERROR (Status)) {
|
|
if (SizeOfVariable == 1) {
|
|
CopyMem (&MapValue, VariableData, 1);
|
|
} else {
|
|
CopyMem (&MapValue, VariableData, 2);
|
|
}
|
|
|
|
PushBool (&StackPtr, (BOOLEAN)!(MapValue == Iterator->Value));
|
|
}
|
|
break;
|
|
|
|
case FRAMEWORK_EFI_IFR_EQ_ID_ID_OP:
|
|
Operator = (BOOLEAN)!(MapValue == MapValue2);
|
|
PushBool (&StackPtr, Operator);
|
|
break;
|
|
|
|
case FRAMEWORK_EFI_IFR_EQ_ID_LIST_OP:
|
|
for (Index = 0; Index < Iterator->ListLength; Index++) {
|
|
Operator = (BOOLEAN)!(MapValue == Iterator->ValueList[Index]);
|
|
if (Operator) {
|
|
continue;
|
|
}
|
|
}
|
|
|
|
PushBool (&StackPtr, Operator);
|
|
break;
|
|
|
|
default:
|
|
return FALSE;
|
|
}
|
|
|
|
Operator = PopBool (&StackPtr);
|
|
Operator2 = PopBool (&StackPtr);
|
|
|
|
if (OrOperator) {
|
|
PushBool (&StackPtr, (BOOLEAN) (Operator || Operator2));
|
|
}
|
|
|
|
if (AndOperator) {
|
|
PushBool (&StackPtr, (BOOLEAN) (Operator && Operator2));
|
|
}
|
|
|
|
if (!OrOperator && !AndOperator) {
|
|
PushBool (&StackPtr, Operator);
|
|
}
|
|
break;
|
|
|
|
case FRAMEWORK_EFI_IFR_TRUE_OP:
|
|
//
|
|
// To check whether Ifr is legacy. Once every boolean expression.
|
|
//
|
|
if (IsLegacy == 0) {
|
|
IsLegacy = PredicateIfrType (Iterator);
|
|
}
|
|
if (IsLegacy == 0x2) {
|
|
PostOrderEvaluate (FileFormTags, Width, &Iterator, &StackPtr);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case FRAMEWORK_EFI_IFR_FALSE_OP:
|
|
//
|
|
// To check whether Ifr is legacy. Once every boolean expression.
|
|
//
|
|
if (IsLegacy == 0) {
|
|
IsLegacy = PredicateIfrType (Iterator);
|
|
}
|
|
if (IsLegacy == 0x2) {
|
|
PostOrderEvaluate (FileFormTags, Width, &Iterator, &StackPtr);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case FRAMEWORK_EFI_IFR_END_IF_OP:
|
|
Operator = PopBool (&StackPtr);
|
|
//
|
|
// If there is an error, return, otherwise keep looking - there might
|
|
// be another test that causes an error
|
|
//
|
|
if (Operator) {
|
|
if (Complex && CosmeticConsistency) {
|
|
return EFI_SUCCESS;
|
|
} else {
|
|
return Operator;
|
|
}
|
|
} else {
|
|
//
|
|
// If not doing a global consistency check, the endif is the REAL terminator of this operation
|
|
// This is used for grayout/suppress operations. InconsistentIf is a global operation so the EndIf is
|
|
// not the end-all be-all of terminators.
|
|
//
|
|
if (!Complex) {
|
|
return Operator;
|
|
}
|
|
break;
|
|
}
|
|
|
|
default:
|
|
//
|
|
// Must have hit a non-consistency related op-code after a suppress/grayout
|
|
//
|
|
if (ArtificialEnd) {
|
|
ArtificialEnd = FALSE;
|
|
Operator = PopBool (&StackPtr);
|
|
return Operator;
|
|
}
|
|
|
|
goto Done;
|
|
}
|
|
|
|
Iterator++;
|
|
}
|
|
|
|
Done:
|
|
return FALSE;
|
|
}
|