2 Utility functions for expression evaluation.
4 Copyright (c) 2007 - 2008, Intel Corporation
5 All rights reserved. This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
19 // Global stack used to evaluate boolean expresions
21 EFI_HII_VALUE
*mOpCodeScopeStack
= NULL
;
22 EFI_HII_VALUE
*mOpCodeScopeStackEnd
= NULL
;
23 EFI_HII_VALUE
*mOpCodeScopeStackPointer
= NULL
;
25 EFI_HII_VALUE
*mExpressionEvaluationStack
= NULL
;
26 EFI_HII_VALUE
*mExpressionEvaluationStackEnd
= NULL
;
27 EFI_HII_VALUE
*mExpressionEvaluationStackPointer
= NULL
;
30 // Unicode collation protocol interface
32 EFI_UNICODE_COLLATION_PROTOCOL
*mUnicodeCollation
= NULL
;
36 Grow size of the stack.
38 This is an internal function.
40 @param Stack On input: old stack; On output: new stack
41 @param StackPtr On input: old stack pointer; On output: new stack
43 @param StackEnd On input: old stack end; On output: new stack end
45 @retval EFI_SUCCESS Grow stack success.
46 @retval EFI_OUT_OF_RESOURCES No enough memory for stack space.
51 IN OUT EFI_HII_VALUE
**Stack
,
52 IN OUT EFI_HII_VALUE
**StackPtr
,
53 IN OUT EFI_HII_VALUE
**StackEnd
57 EFI_HII_VALUE
*NewStack
;
59 Size
= EXPRESSION_STACK_SIZE_INCREMENT
;
60 if (*StackPtr
!= NULL
) {
61 Size
= Size
+ (*StackEnd
- *Stack
);
64 NewStack
= AllocatePool (Size
* sizeof (EFI_HII_VALUE
));
65 if (NewStack
== NULL
) {
66 return EFI_OUT_OF_RESOURCES
;
69 if (*StackPtr
!= NULL
) {
71 // Copy from Old Stack to the New Stack
76 (*StackEnd
- *Stack
) * sizeof (EFI_HII_VALUE
)
86 // Make the Stack pointer point to the old data in the new stack
88 *StackPtr
= NewStack
+ (*StackPtr
- *Stack
);
90 *StackEnd
= NewStack
+ Size
;
97 Push an element onto the Boolean Stack.
99 @param Stack On input: old stack; On output: new stack
100 @param StackPtr On input: old stack pointer; On output: new stack
102 @param StackEnd On input: old stack end; On output: new stack end
103 @param Data Data to push.
105 @retval EFI_SUCCESS Push stack success.
110 IN OUT EFI_HII_VALUE
**Stack
,
111 IN OUT EFI_HII_VALUE
**StackPtr
,
112 IN OUT EFI_HII_VALUE
**StackEnd
,
113 IN EFI_HII_VALUE
*Data
119 // Check for a stack overflow condition
121 if (*StackPtr
>= *StackEnd
) {
125 Status
= GrowStack (Stack
, StackPtr
, StackEnd
);
126 if (EFI_ERROR (Status
)) {
132 // Push the item onto the stack
134 CopyMem (*StackPtr
, Data
, sizeof (EFI_HII_VALUE
));
135 *StackPtr
= *StackPtr
+ 1;
142 Pop an element from the stack.
144 @param Stack On input: old stack; On output: new stack
145 @param StackPtr On input: old stack pointer; On output: new stack
147 @param StackEnd On input: old stack end; On output: new stack end
148 @param Data Data to pop.
150 @retval EFI_SUCCESS The value was popped onto the stack.
151 @retval EFI_ACCESS_DENIED The pop operation underflowed the stack
156 IN OUT EFI_HII_VALUE
**Stack
,
157 IN OUT EFI_HII_VALUE
**StackPtr
,
158 IN OUT EFI_HII_VALUE
**StackEnd
,
159 OUT EFI_HII_VALUE
*Data
163 // Check for a stack underflow condition
165 if (*StackPtr
== *Stack
) {
166 return EFI_ACCESS_DENIED
;
170 // Pop the item off the stack
172 *StackPtr
= *StackPtr
- 1;
173 CopyMem (Data
, *StackPtr
, sizeof (EFI_HII_VALUE
));
179 Reset stack pointer to begin of the stack.
187 mOpCodeScopeStackPointer
= mOpCodeScopeStack
;
192 Push an Operand onto the Stack
194 @param Operand Operand to push.
196 @retval EFI_SUCCESS The value was pushed onto the stack.
197 @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the
208 Data
.Type
= EFI_IFR_TYPE_NUM_SIZE_8
;
209 Data
.Value
.u8
= Operand
;
213 &mOpCodeScopeStackPointer
,
214 &mOpCodeScopeStackEnd
,
221 Pop an Operand from the Stack
223 @param Operand Operand to pop.
225 @retval EFI_SUCCESS The value was pushed onto the stack.
226 @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the
240 &mOpCodeScopeStackPointer
,
241 &mOpCodeScopeStackEnd
,
245 *Operand
= Data
.Value
.u8
;
252 Reset stack pointer to begin of the stack.
256 ResetExpressionStack (
260 mExpressionEvaluationStackPointer
= mExpressionEvaluationStack
;
265 Push an Expression value onto the Stack
267 @param Value Expression value to push.
269 @retval EFI_SUCCESS The value was pushed onto the stack.
270 @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the
276 IN EFI_HII_VALUE
*Value
280 &mExpressionEvaluationStack
,
281 &mExpressionEvaluationStackPointer
,
282 &mExpressionEvaluationStackEnd
,
289 Pop an Expression value from the stack.
291 @param Value Expression value to pop.
293 @retval EFI_SUCCESS The value was popped onto the stack.
294 @retval EFI_ACCESS_DENIED The pop operation underflowed the stack
299 OUT EFI_HII_VALUE
*Value
303 &mExpressionEvaluationStack
,
304 &mExpressionEvaluationStackPointer
,
305 &mExpressionEvaluationStackEnd
,
312 Get Form given its FormId.
314 @param FormSet The formset which contains this form.
315 @param FormId Id of this form.
317 @retval Pointer The form.
318 @retval NULL Specified Form is not found in the formset.
323 IN FORM_BROWSER_FORMSET
*FormSet
,
328 FORM_BROWSER_FORM
*Form
;
330 Link
= GetFirstNode (&FormSet
->FormListHead
);
331 while (!IsNull (&FormSet
->FormListHead
, Link
)) {
332 Form
= FORM_BROWSER_FORM_FROM_LINK (Link
);
334 if (Form
->FormId
== FormId
) {
338 Link
= GetNextNode (&FormSet
->FormListHead
, Link
);
346 Search a Question in Form scope using its QuestionId.
348 @param Form The form which contains this Question.
349 @param QuestionId Id of this Question.
351 @retval Pointer The Question.
352 @retval NULL Specified Question not found in the form.
355 FORM_BROWSER_STATEMENT
*
357 IN FORM_BROWSER_FORM
*Form
,
362 FORM_BROWSER_STATEMENT
*Question
;
364 if (QuestionId
== 0) {
366 // The value of zero is reserved
371 Link
= GetFirstNode (&Form
->StatementListHead
);
372 while (!IsNull (&Form
->StatementListHead
, Link
)) {
373 Question
= FORM_BROWSER_STATEMENT_FROM_LINK (Link
);
375 if (Question
->QuestionId
== QuestionId
) {
379 Link
= GetNextNode (&Form
->StatementListHead
, Link
);
387 Search a Question in Formset scope using its QuestionId.
389 @param FormSet The formset which contains this form.
390 @param Form The form which contains this Question.
391 @param QuestionId Id of this Question.
393 @retval Pointer The Question.
394 @retval NULL Specified Question not found in the form.
397 FORM_BROWSER_STATEMENT
*
399 IN FORM_BROWSER_FORMSET
*FormSet
,
400 IN FORM_BROWSER_FORM
*Form
,
405 FORM_BROWSER_STATEMENT
*Question
;
408 // Search in the form scope first
410 Question
= IdToQuestion2 (Form
, QuestionId
);
411 if (Question
!= NULL
) {
416 // Search in the formset scope
418 Link
= GetFirstNode (&FormSet
->FormListHead
);
419 while (!IsNull (&FormSet
->FormListHead
, Link
)) {
420 Form
= FORM_BROWSER_FORM_FROM_LINK (Link
);
422 Question
= IdToQuestion2 (Form
, QuestionId
);
423 if (Question
!= NULL
) {
425 // EFI variable storage may be updated by Callback() asynchronous,
426 // to keep synchronous, always reload the Question Value.
428 if (Question
->Storage
->Type
== EFI_HII_VARSTORE_EFI_VARIABLE
) {
429 GetQuestionValue (FormSet
, Form
, Question
, FALSE
);
435 Link
= GetNextNode (&FormSet
->FormListHead
, Link
);
443 Get Expression given its RuleId.
445 @param Form The form which contains this Expression.
446 @param RuleId Id of this Expression.
448 @retval Pointer The Expression.
449 @retval NULL Specified Expression not found in the form.
454 IN FORM_BROWSER_FORM
*Form
,
459 FORM_EXPRESSION
*Expression
;
461 Link
= GetFirstNode (&Form
->ExpressionListHead
);
462 while (!IsNull (&Form
->ExpressionListHead
, Link
)) {
463 Expression
= FORM_EXPRESSION_FROM_LINK (Link
);
465 if (Expression
->Type
== EFI_HII_EXPRESSION_RULE
&& Expression
->RuleId
== RuleId
) {
469 Link
= GetNextNode (&Form
->ExpressionListHead
, Link
);
477 Locate the Unicode Collation Protocol interface for later use.
479 @retval EFI_SUCCESS Protocol interface initialize success.
480 @retval Other Protocol interface initialize failed.
484 InitializeUnicodeCollationProtocol (
490 if (mUnicodeCollation
!= NULL
) {
495 // BUGBUG: Proper impelmentation is to locate all Unicode Collation Protocol
496 // instances first and then select one which support English language.
497 // Current implementation just pick the first instance.
499 Status
= gBS
->LocateProtocol (
500 &gEfiUnicodeCollation2ProtocolGuid
,
502 (VOID
**) &mUnicodeCollation
508 Convert the input Unicode character to upper.
510 @param String Th Unicode character to be converted.
518 while (*String
!= 0) {
519 if ((*String
>= 'a') && (*String
<= 'z')) {
520 *String
= (UINT16
) ((*String
) & ((UINT16
) ~0x20));
528 Evaluate opcode EFI_IFR_TO_STRING.
530 @param FormSet Formset which contains this opcode.
531 @param Format String format in EFI_IFR_TO_STRING.
532 @param Result Evaluation result for this opcode.
534 @retval EFI_SUCCESS Opcode evaluation success.
535 @retval Other Opcode evaluation failed.
540 IN FORM_BROWSER_FORMSET
*FormSet
,
542 OUT EFI_HII_VALUE
*Result
549 CHAR16 Buffer
[MAXIMUM_VALUE_CHARACTERS
];
552 Status
= PopExpression (&Value
);
553 if (EFI_ERROR (Status
)) {
557 switch (Value
.Type
) {
558 case EFI_IFR_TYPE_NUM_SIZE_8
:
559 case EFI_IFR_TYPE_NUM_SIZE_16
:
560 case EFI_IFR_TYPE_NUM_SIZE_32
:
561 case EFI_IFR_TYPE_NUM_SIZE_64
:
562 BufferSize
= MAXIMUM_VALUE_CHARACTERS
* sizeof (CHAR16
);
564 case EFI_IFR_STRING_UNSIGNED_DEC
:
565 case EFI_IFR_STRING_SIGNED_DEC
:
566 PrintFormat
= L
"%ld";
569 case EFI_IFR_STRING_LOWERCASE_HEX
:
570 PrintFormat
= L
"%lx";
573 case EFI_IFR_STRING_UPPERCASE_HEX
:
574 PrintFormat
= L
"%lX";
578 return EFI_UNSUPPORTED
;
580 UnicodeSPrint (Buffer
, BufferSize
, PrintFormat
, Value
.Value
.u64
);
584 case EFI_IFR_TYPE_STRING
:
585 CopyMem (Result
, &Value
, sizeof (EFI_HII_VALUE
));
588 case EFI_IFR_TYPE_BOOLEAN
:
589 String
= (Value
.Value
.b
) ? L
"True" : L
"False";
593 return EFI_UNSUPPORTED
;
596 Result
->Type
= EFI_IFR_TYPE_STRING
;
597 Result
->Value
.string
= NewString (String
, FormSet
->HiiHandle
);
603 Evaluate opcode EFI_IFR_TO_UINT.
605 @param FormSet Formset which contains this opcode.
606 @param Result Evaluation result for this opcode.
608 @retval EFI_SUCCESS Opcode evaluation success.
609 @retval Other Opcode evaluation failed.
614 IN FORM_BROWSER_FORMSET
*FormSet
,
615 OUT EFI_HII_VALUE
*Result
623 Status
= PopExpression (&Value
);
624 if (EFI_ERROR (Status
)) {
628 if (Value
.Type
>= EFI_IFR_TYPE_OTHER
) {
629 return EFI_UNSUPPORTED
;
632 Status
= EFI_SUCCESS
;
633 if (Value
.Type
== EFI_IFR_TYPE_STRING
) {
634 String
= GetToken (Value
.Value
.string
, FormSet
->HiiHandle
);
635 if (String
== NULL
) {
636 return EFI_NOT_FOUND
;
639 IfrStrToUpper (String
);
640 StringPtr
= StrStr (String
, L
"0X");
641 if (StringPtr
!= NULL
) {
645 Result
->Value
.u64
= StrHexToUint64 (String
);
650 Result
->Value
.u64
= StrDecimalToUint64 (String
);
654 CopyMem (Result
, &Value
, sizeof (EFI_HII_VALUE
));
657 Result
->Type
= EFI_IFR_TYPE_NUM_SIZE_64
;
663 Evaluate opcode EFI_IFR_CATENATE.
665 @param FormSet Formset which contains this opcode.
666 @param Result Evaluation result for this opcode.
668 @retval EFI_SUCCESS Opcode evaluation success.
669 @retval Other Opcode evaluation failed.
674 IN FORM_BROWSER_FORMSET
*FormSet
,
675 OUT EFI_HII_VALUE
*Result
686 // String[0] - The second string
687 // String[1] - The first string
692 Status
= EFI_SUCCESS
;
694 for (Index
= 0; Index
< 2; Index
++) {
695 Status
= PopExpression (&Value
);
696 if (EFI_ERROR (Status
)) {
700 if (Value
.Type
!= EFI_IFR_TYPE_STRING
) {
701 Status
= EFI_UNSUPPORTED
;
705 String
[Index
] = GetToken (Value
.Value
.string
, FormSet
->HiiHandle
);
707 Status
= EFI_NOT_FOUND
;
712 Size
= StrSize (String
[0]);
713 StringPtr
= AllocatePool (StrSize (String
[1]) + Size
);
714 ASSERT (StringPtr
!= NULL
);
715 StrCpy (StringPtr
, String
[1]);
716 StrCat (StringPtr
, String
[0]);
718 Result
->Type
= EFI_IFR_TYPE_STRING
;
719 Result
->Value
.string
= NewString (StringPtr
, FormSet
->HiiHandle
);
722 if (String
[0] != NULL
) {
723 FreePool (String
[0]);
725 if (String
[1] != NULL
) {
726 FreePool (String
[1]);
728 if (StringPtr
!= NULL
) {
729 FreePool (StringPtr
);
737 Evaluate opcode EFI_IFR_MATCH.
739 @param FormSet Formset which contains this opcode.
740 @param Result Evaluation result for this opcode.
742 @retval EFI_SUCCESS Opcode evaluation success.
743 @retval Other Opcode evaluation failed.
748 IN FORM_BROWSER_FORMSET
*FormSet
,
749 OUT EFI_HII_VALUE
*Result
758 // String[0] - The string to search
759 // String[1] - pattern
763 Status
= EFI_SUCCESS
;
764 for (Index
= 0; Index
< 2; Index
++) {
765 Status
= PopExpression (&Value
);
766 if (EFI_ERROR (Status
)) {
770 if (Value
.Type
!= EFI_IFR_TYPE_STRING
) {
771 Status
= EFI_UNSUPPORTED
;
775 String
[Index
] = GetToken (Value
.Value
.string
, FormSet
->HiiHandle
);
777 Status
= EFI_NOT_FOUND
;
782 Result
->Type
= EFI_IFR_TYPE_BOOLEAN
;
783 Result
->Value
.b
= mUnicodeCollation
->MetaiMatch (mUnicodeCollation
, String
[0], String
[1]);
786 if (String
[0] != NULL
) {
787 FreePool (String
[0]);
789 if (String
[1] != NULL
) {
790 FreePool (String
[1]);
798 Evaluate opcode EFI_IFR_FIND.
800 @param FormSet Formset which contains this opcode.
801 @param Format Case sensitive or insensitive.
802 @param Result Evaluation result for this opcode.
804 @retval EFI_SUCCESS Opcode evaluation success.
805 @retval Other Opcode evaluation failed.
810 IN FORM_BROWSER_FORMSET
*FormSet
,
812 OUT EFI_HII_VALUE
*Result
822 if (Format
> EFI_IFR_FF_CASE_INSENSITIVE
) {
823 return EFI_UNSUPPORTED
;
826 Status
= PopExpression (&Value
);
827 if (EFI_ERROR (Status
)) {
830 if (Value
.Type
> EFI_IFR_TYPE_NUM_SIZE_64
) {
831 return EFI_UNSUPPORTED
;
833 Base
= (UINTN
) Value
.Value
.u64
;
836 // String[0] - sub-string
837 // String[1] - The string to search
841 for (Index
= 0; Index
< 2; Index
++) {
842 Status
= PopExpression (&Value
);
843 if (EFI_ERROR (Status
)) {
847 if (Value
.Type
!= EFI_IFR_TYPE_STRING
) {
848 Status
= EFI_UNSUPPORTED
;
852 String
[Index
] = GetToken (Value
.Value
.string
, FormSet
->HiiHandle
);
854 Status
= EFI_NOT_FOUND
;
858 if (Format
== EFI_IFR_FF_CASE_INSENSITIVE
) {
860 // Case insensitive, convert both string to upper case
862 IfrStrToUpper (String
[Index
]);
866 Result
->Type
= EFI_IFR_TYPE_NUM_SIZE_64
;
867 if (Base
>= StrLen (String
[1])) {
868 Result
->Value
.u64
= 0xFFFFFFFFFFFFFFFFULL
;
870 StringPtr
= StrStr (String
[1] + Base
, String
[0]);
871 Result
->Value
.u64
= (StringPtr
== NULL
) ? 0xFFFFFFFFFFFFFFFFULL
: (StringPtr
- String
[1]);
875 if (String
[0] != NULL
) {
876 FreePool (String
[0]);
878 if (String
[1] != NULL
) {
879 FreePool (String
[1]);
887 Evaluate opcode EFI_IFR_MID.
889 @param FormSet Formset which contains this opcode.
890 @param Result Evaluation result for this opcode.
892 @retval EFI_SUCCESS Opcode evaluation success.
893 @retval Other Opcode evaluation failed.
898 IN FORM_BROWSER_FORMSET
*FormSet
,
899 OUT EFI_HII_VALUE
*Result
909 Status
= PopExpression (&Value
);
910 if (EFI_ERROR (Status
)) {
913 if (Value
.Type
> EFI_IFR_TYPE_NUM_SIZE_64
) {
914 return EFI_UNSUPPORTED
;
916 Length
= (UINTN
) Value
.Value
.u64
;
918 Status
= PopExpression (&Value
);
919 if (EFI_ERROR (Status
)) {
922 if (Value
.Type
> EFI_IFR_TYPE_NUM_SIZE_64
) {
923 return EFI_UNSUPPORTED
;
925 Base
= (UINTN
) Value
.Value
.u64
;
927 Status
= PopExpression (&Value
);
928 if (EFI_ERROR (Status
)) {
931 if (Value
.Type
!= EFI_IFR_TYPE_STRING
) {
932 return EFI_UNSUPPORTED
;
934 String
= GetToken (Value
.Value
.string
, FormSet
->HiiHandle
);
935 if (String
== NULL
) {
936 return EFI_NOT_FOUND
;
939 if (Length
== 0 || Base
>= StrLen (String
)) {
940 SubString
= gEmptyString
;
942 SubString
= String
+ Base
;
943 if ((Base
+ Length
) < StrLen (String
)) {
944 SubString
[Length
] = L
'\0';
948 Result
->Type
= EFI_IFR_TYPE_STRING
;
949 Result
->Value
.string
= NewString (SubString
, FormSet
->HiiHandle
);
958 Evaluate opcode EFI_IFR_TOKEN.
960 @param FormSet Formset which contains this opcode.
961 @param Result Evaluation result for this opcode.
963 @retval EFI_SUCCESS Opcode evaluation success.
964 @retval Other Opcode evaluation failed.
969 IN FORM_BROWSER_FORMSET
*FormSet
,
970 OUT EFI_HII_VALUE
*Result
982 Status
= PopExpression (&Value
);
983 if (EFI_ERROR (Status
)) {
986 if (Value
.Type
> EFI_IFR_TYPE_NUM_SIZE_64
) {
987 return EFI_UNSUPPORTED
;
989 Count
= (UINTN
) Value
.Value
.u64
;
992 // String[0] - Delimiter
993 // String[1] - The string to search
997 for (Index
= 0; Index
< 2; Index
++) {
998 Status
= PopExpression (&Value
);
999 if (EFI_ERROR (Status
)) {
1003 if (Value
.Type
!= EFI_IFR_TYPE_STRING
) {
1004 Status
= EFI_UNSUPPORTED
;
1008 String
[Index
] = GetToken (Value
.Value
.string
, FormSet
->HiiHandle
);
1009 if (String
== NULL
) {
1010 Status
= EFI_NOT_FOUND
;
1015 Delimiter
= String
[0];
1016 SubString
= String
[1];
1018 SubString
= StrStr (SubString
, Delimiter
);
1019 if (SubString
!= NULL
) {
1021 // Skip over the delimiter
1023 SubString
= SubString
+ StrLen (Delimiter
);
1030 if (SubString
== NULL
) {
1032 // nth delimited sub-string not found, push an empty string
1034 SubString
= gEmptyString
;
1037 // Put a NULL terminator for nth delimited sub-string
1039 StringPtr
= StrStr (SubString
, Delimiter
);
1040 if (StringPtr
!= NULL
) {
1045 Result
->Type
= EFI_IFR_TYPE_STRING
;
1046 Result
->Value
.string
= NewString (SubString
, FormSet
->HiiHandle
);
1049 if (String
[0] != NULL
) {
1050 FreePool (String
[0]);
1052 if (String
[1] != NULL
) {
1053 FreePool (String
[1]);
1061 Evaluate opcode EFI_IFR_SPAN.
1063 @param FormSet Formset which contains this opcode.
1064 @param Flags FIRST_MATCHING or FIRST_NON_MATCHING.
1065 @param Result Evaluation result for this opcode.
1067 @retval EFI_SUCCESS Opcode evaluation success.
1068 @retval Other Opcode evaluation failed.
1073 IN FORM_BROWSER_FORMSET
*FormSet
,
1075 OUT EFI_HII_VALUE
*Result
1079 EFI_HII_VALUE Value
;
1087 Status
= PopExpression (&Value
);
1088 if (EFI_ERROR (Status
)) {
1091 if (Value
.Type
> EFI_IFR_TYPE_NUM_SIZE_64
) {
1092 return EFI_UNSUPPORTED
;
1094 Base
= (UINTN
) Value
.Value
.u64
;
1097 // String[0] - Charset
1098 // String[1] - The string to search
1102 for (Index
= 0; Index
< 2; Index
++) {
1103 Status
= PopExpression (&Value
);
1104 if (EFI_ERROR (Status
)) {
1108 if (Value
.Type
!= EFI_IFR_TYPE_STRING
) {
1109 Status
= EFI_UNSUPPORTED
;
1113 String
[Index
] = GetToken (Value
.Value
.string
, FormSet
->HiiHandle
);
1114 if (String
== NULL
) {
1115 Status
= EFI_NOT_FOUND
;
1120 if (Base
>= StrLen (String
[1])) {
1121 Status
= EFI_UNSUPPORTED
;
1126 StringPtr
= String
[1] + Base
;
1127 Charset
= String
[0];
1128 while (*StringPtr
!= 0 && !Found
) {
1130 while (Charset
[Index
] != 0) {
1131 if (*StringPtr
>= Charset
[Index
] && *StringPtr
<= Charset
[Index
+ 1]) {
1132 if (Flags
== EFI_IFR_FLAGS_FIRST_MATCHING
) {
1137 if (Flags
== EFI_IFR_FLAGS_FIRST_NON_MATCHING
) {
1143 // Skip characters pair representing low-end of a range and high-end of a range
1153 Result
->Type
= EFI_IFR_TYPE_NUM_SIZE_64
;
1154 Result
->Value
.u64
= StringPtr
- String
[1];
1157 if (String
[0] != NULL
) {
1158 FreePool (String
[0]);
1160 if (String
[1] != NULL
) {
1161 FreePool (String
[1]);
1169 Zero extend integer/boolean/date/time to UINT64 for comparing.
1171 @param Value HII Value to be converted.
1176 IN EFI_HII_VALUE
*Value
1182 switch (Value
->Type
) {
1183 case EFI_IFR_TYPE_NUM_SIZE_8
:
1184 Temp
= Value
->Value
.u8
;
1187 case EFI_IFR_TYPE_NUM_SIZE_16
:
1188 Temp
= Value
->Value
.u16
;
1191 case EFI_IFR_TYPE_NUM_SIZE_32
:
1192 Temp
= Value
->Value
.u32
;
1195 case EFI_IFR_TYPE_BOOLEAN
:
1196 Temp
= Value
->Value
.b
;
1199 case EFI_IFR_TYPE_TIME
:
1200 Temp
= Value
->Value
.u32
& 0xffffff;
1203 case EFI_IFR_TYPE_DATE
:
1204 Temp
= Value
->Value
.u32
;
1211 Value
->Value
.u64
= Temp
;
1216 Compare two Hii value.
1218 @param Value1 Expression value to compare on left-hand.
1219 @param Value2 Expression value to compare on right-hand.
1220 @param HiiHandle Only required for string compare.
1222 @retval EFI_INVALID_PARAMETER Could not perform comparation on two values.
1223 @retval 0 Two operators equeal.
1224 @return Positive value if Value1 is greater than Value2.
1225 @retval Negative value if Value1 is less than Value2.
1230 IN EFI_HII_VALUE
*Value1
,
1231 IN EFI_HII_VALUE
*Value2
,
1232 IN EFI_HII_HANDLE HiiHandle OPTIONAL
1240 if (Value1
->Type
>= EFI_IFR_TYPE_OTHER
|| Value2
->Type
>= EFI_IFR_TYPE_OTHER
) {
1241 return EFI_INVALID_PARAMETER
;
1244 if (Value1
->Type
== EFI_IFR_TYPE_STRING
|| Value2
->Type
== EFI_IFR_TYPE_STRING
) {
1245 if (Value1
->Type
!= Value2
->Type
) {
1247 // Both Operator should be type of String
1249 return EFI_INVALID_PARAMETER
;
1252 if (Value1
->Value
.string
== 0 || Value2
->Value
.string
== 0) {
1254 // StringId 0 is reserved
1256 return EFI_INVALID_PARAMETER
;
1259 if (Value1
->Value
.string
== Value2
->Value
.string
) {
1263 Str1
= GetToken (Value1
->Value
.string
, HiiHandle
);
1268 return EFI_INVALID_PARAMETER
;
1271 Str2
= GetToken (Value2
->Value
.string
, HiiHandle
);
1274 return EFI_INVALID_PARAMETER
;
1277 Result
= StrCmp (Str1
, Str2
);
1286 // Take remain types(integer, boolean, date/time) as integer
1288 Temp64
= (INT64
) (Value1
->Value
.u64
- Value2
->Value
.u64
);
1291 } else if (Temp64
< 0) {
1302 Evaluate the result of a HII expression
1304 @param FormSet FormSet associated with this expression.
1305 @param Form Form associated with this expression.
1306 @param Expression Expression to be evaluated.
1308 @retval EFI_SUCCESS The expression evaluated successfuly
1309 @retval EFI_NOT_FOUND The Question which referenced by a QuestionId
1311 @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the
1313 @retval EFI_ACCESS_DENIED The pop operation underflowed the stack
1314 @retval EFI_INVALID_PARAMETER Syntax error with the Expression
1318 EvaluateExpression (
1319 IN FORM_BROWSER_FORMSET
*FormSet
,
1320 IN FORM_BROWSER_FORM
*Form
,
1321 IN OUT FORM_EXPRESSION
*Expression
1326 EXPRESSION_OPCODE
*OpCode
;
1327 FORM_BROWSER_STATEMENT
*Question
;
1328 FORM_BROWSER_STATEMENT
*Question2
;
1330 EFI_HII_VALUE Data1
;
1331 EFI_HII_VALUE Data2
;
1332 EFI_HII_VALUE Data3
;
1333 FORM_EXPRESSION
*RuleExpression
;
1334 EFI_HII_VALUE
*Value
;
1340 // Always reset the stack before evaluating an Expression
1342 ResetExpressionStack ();
1344 Expression
->Result
.Type
= EFI_IFR_TYPE_OTHER
;
1346 Link
= GetFirstNode (&Expression
->OpCodeListHead
);
1347 while (!IsNull (&Expression
->OpCodeListHead
, Link
)) {
1348 OpCode
= EXPRESSION_OPCODE_FROM_LINK (Link
);
1350 Link
= GetNextNode (&Expression
->OpCodeListHead
, Link
);
1352 ZeroMem (&Data1
, sizeof (EFI_HII_VALUE
));
1353 ZeroMem (&Data2
, sizeof (EFI_HII_VALUE
));
1354 ZeroMem (&Data3
, sizeof (EFI_HII_VALUE
));
1357 Value
->Type
= EFI_IFR_TYPE_BOOLEAN
;
1358 Status
= EFI_SUCCESS
;
1360 switch (OpCode
->Operand
) {
1362 // Built-in functions
1364 case EFI_IFR_EQ_ID_VAL_OP
:
1365 Question
= IdToQuestion (FormSet
, Form
, OpCode
->QuestionId
);
1366 if (Question
== NULL
) {
1367 return EFI_NOT_FOUND
;
1370 Result
= CompareHiiValue (&Question
->HiiValue
, &OpCode
->Value
, NULL
);
1371 if (Result
== EFI_INVALID_PARAMETER
) {
1372 return EFI_INVALID_PARAMETER
;
1374 Value
->Value
.b
= (BOOLEAN
) ((Result
== 0) ? TRUE
: FALSE
);
1377 case EFI_IFR_EQ_ID_ID_OP
:
1378 Question
= IdToQuestion (FormSet
, Form
, OpCode
->QuestionId
);
1379 if (Question
== NULL
) {
1380 return EFI_NOT_FOUND
;
1383 Question2
= IdToQuestion (FormSet
, Form
, OpCode
->QuestionId2
);
1384 if (Question2
== NULL
) {
1385 return EFI_NOT_FOUND
;
1388 Result
= CompareHiiValue (&Question
->HiiValue
, &Question2
->HiiValue
, FormSet
->HiiHandle
);
1389 if (Result
== EFI_INVALID_PARAMETER
) {
1390 return EFI_INVALID_PARAMETER
;
1392 Value
->Value
.b
= (BOOLEAN
) ((Result
== 0) ? TRUE
: FALSE
);
1395 case EFI_IFR_EQ_ID_LIST_OP
:
1396 Question
= IdToQuestion (FormSet
, Form
, OpCode
->QuestionId
);
1397 if (Question
== NULL
) {
1398 return EFI_NOT_FOUND
;
1401 Value
->Value
.b
= FALSE
;
1402 for (Index
=0; Index
< OpCode
->ListLength
; Index
++) {
1403 if (Question
->HiiValue
.Value
.u16
== OpCode
->ValueList
[Index
]) {
1404 Value
->Value
.b
= TRUE
;
1410 case EFI_IFR_DUP_OP
:
1411 Status
= PopExpression (Value
);
1412 if (EFI_ERROR (Status
)) {
1416 Status
= PushExpression (Value
);
1419 case EFI_IFR_QUESTION_REF1_OP
:
1420 case EFI_IFR_THIS_OP
:
1421 Question
= IdToQuestion (FormSet
, Form
, OpCode
->QuestionId
);
1422 if (Question
== NULL
) {
1423 return EFI_NOT_FOUND
;
1426 Value
= &Question
->HiiValue
;
1429 case EFI_IFR_QUESTION_REF3_OP
:
1430 if (OpCode
->DevicePath
== 0) {
1432 // EFI_IFR_QUESTION_REF3
1433 // Pop an expression from the expression stack
1435 Status
= PopExpression (Value
);
1436 if (EFI_ERROR (Status
)) {
1441 // Validate the expression value
1443 if ((Value
->Type
> EFI_IFR_TYPE_NUM_SIZE_64
) || (Value
->Value
.u64
> 0xffff)) {
1444 return EFI_NOT_FOUND
;
1447 Question
= IdToQuestion (FormSet
, Form
, Value
->Value
.u16
);
1448 if (Question
== NULL
) {
1449 return EFI_NOT_FOUND
;
1453 // push the questions' value on to the expression stack
1455 Value
= &Question
->HiiValue
;
1458 // BUGBUG: push 0 for EFI_IFR_QUESTION_REF3_2 and EFI_IFR_QUESTION_REF3_3,
1459 // since it is impractical to evaluate the value of a Question in another
1460 // Hii Package list.
1462 ZeroMem (Value
, sizeof (EFI_HII_VALUE
));
1466 case EFI_IFR_RULE_REF_OP
:
1468 // Find expression for this rule
1470 RuleExpression
= RuleIdToExpression (Form
, OpCode
->RuleId
);
1471 if (RuleExpression
== NULL
) {
1472 return EFI_NOT_FOUND
;
1476 // Evaluate this rule expression
1478 Status
= EvaluateExpression (FormSet
, Form
, RuleExpression
);
1479 if (EFI_ERROR (Status
)) {
1483 Value
= &RuleExpression
->Result
;
1486 case EFI_IFR_STRING_REF1_OP
:
1487 Value
->Type
= EFI_IFR_TYPE_STRING
;
1488 Value
->Value
.string
= OpCode
->Value
.Value
.string
;
1494 case EFI_IFR_TRUE_OP
:
1495 case EFI_IFR_FALSE_OP
:
1496 case EFI_IFR_ONE_OP
:
1497 case EFI_IFR_ONES_OP
:
1498 case EFI_IFR_UINT8_OP
:
1499 case EFI_IFR_UINT16_OP
:
1500 case EFI_IFR_UINT32_OP
:
1501 case EFI_IFR_UINT64_OP
:
1502 case EFI_IFR_UNDEFINED_OP
:
1503 case EFI_IFR_VERSION_OP
:
1504 case EFI_IFR_ZERO_OP
:
1505 Value
= &OpCode
->Value
;
1511 case EFI_IFR_LENGTH_OP
:
1512 Status
= PopExpression (Value
);
1513 if (EFI_ERROR (Status
)) {
1516 if (Value
->Type
!= EFI_IFR_TYPE_STRING
) {
1517 return EFI_INVALID_PARAMETER
;
1520 StrPtr
= GetToken (Value
->Value
.string
, FormSet
->HiiHandle
);
1521 if (StrPtr
== NULL
) {
1522 return EFI_INVALID_PARAMETER
;
1525 Value
->Type
= EFI_IFR_TYPE_NUM_SIZE_64
;
1526 Value
->Value
.u64
= StrLen (StrPtr
);
1530 case EFI_IFR_NOT_OP
:
1531 Status
= PopExpression (Value
);
1532 if (EFI_ERROR (Status
)) {
1535 if (Value
->Type
!= EFI_IFR_TYPE_BOOLEAN
) {
1536 return EFI_INVALID_PARAMETER
;
1538 Value
->Value
.b
= (BOOLEAN
) (!Value
->Value
.b
);
1541 case EFI_IFR_QUESTION_REF2_OP
:
1543 // Pop an expression from the expression stack
1545 Status
= PopExpression (Value
);
1546 if (EFI_ERROR (Status
)) {
1551 // Validate the expression value
1553 if ((Value
->Type
> EFI_IFR_TYPE_NUM_SIZE_64
) || (Value
->Value
.u64
> 0xffff)) {
1554 return EFI_NOT_FOUND
;
1557 Question
= IdToQuestion (FormSet
, Form
, Value
->Value
.u16
);
1558 if (Question
== NULL
) {
1559 return EFI_NOT_FOUND
;
1562 Value
= &Question
->HiiValue
;
1565 case EFI_IFR_STRING_REF2_OP
:
1567 // Pop an expression from the expression stack
1569 Status
= PopExpression (Value
);
1570 if (EFI_ERROR (Status
)) {
1575 // Validate the expression value
1577 if ((Value
->Type
> EFI_IFR_TYPE_NUM_SIZE_64
) || (Value
->Value
.u64
> 0xffff)) {
1578 return EFI_NOT_FOUND
;
1581 Value
->Type
= EFI_IFR_TYPE_STRING
;
1582 StrPtr
= GetToken (Value
->Value
.u16
, FormSet
->HiiHandle
);
1583 if (StrPtr
== NULL
) {
1585 // If String not exit, push an empty string
1587 Value
->Value
.string
= NewString (gEmptyString
, FormSet
->HiiHandle
);
1589 Index
= (UINT16
) Value
->Value
.u64
;
1590 Value
->Value
.string
= Index
;
1595 case EFI_IFR_TO_BOOLEAN_OP
:
1597 // Pop an expression from the expression stack
1599 Status
= PopExpression (Value
);
1600 if (EFI_ERROR (Status
)) {
1605 // Convert an expression to a Boolean
1607 if (Value
->Type
<= EFI_IFR_TYPE_DATE
) {
1609 // When converting from an unsigned integer, zero will be converted to
1610 // FALSE and any other value will be converted to TRUE.
1612 Value
->Value
.b
= (BOOLEAN
) ((Value
->Value
.u64
) ? TRUE
: FALSE
);
1614 Value
->Type
= EFI_IFR_TYPE_BOOLEAN
;
1615 } else if (Value
->Type
== EFI_IFR_TYPE_STRING
) {
1617 // When converting from a string, if case-insensitive compare
1618 // with "true" is True, then push True. If a case-insensitive compare
1619 // with "false" is True, then push False.
1621 StrPtr
= GetToken (Value
->Value
.string
, FormSet
->HiiHandle
);
1622 if (StrPtr
== NULL
) {
1623 return EFI_INVALID_PARAMETER
;
1626 if ((StrCmp (StrPtr
, L
"true") == 0) || (StrCmp (StrPtr
, L
"false") == 0)){
1627 Value
->Value
.b
= TRUE
;
1629 Value
->Value
.b
= FALSE
;
1632 Value
->Type
= EFI_IFR_TYPE_BOOLEAN
;
1636 case EFI_IFR_TO_STRING_OP
:
1637 Status
= IfrToString (FormSet
, OpCode
->Format
, Value
);
1640 case EFI_IFR_TO_UINT_OP
:
1641 Status
= IfrToUint (FormSet
, Value
);
1644 case EFI_IFR_TO_LOWER_OP
:
1645 case EFI_IFR_TO_UPPER_OP
:
1646 Status
= InitializeUnicodeCollationProtocol ();
1647 if (EFI_ERROR (Status
)) {
1651 Status
= PopExpression (Value
);
1652 if (EFI_ERROR (Status
)) {
1656 if (Value
->Type
!= EFI_IFR_TYPE_STRING
) {
1657 return EFI_UNSUPPORTED
;
1660 StrPtr
= GetToken (Value
->Value
.string
, FormSet
->HiiHandle
);
1661 if (StrPtr
== NULL
) {
1662 return EFI_NOT_FOUND
;
1665 if (OpCode
->Operand
== EFI_IFR_TO_LOWER_OP
) {
1666 mUnicodeCollation
->StrLwr (mUnicodeCollation
, StrPtr
);
1668 mUnicodeCollation
->StrUpr (mUnicodeCollation
, StrPtr
);
1670 Value
->Value
.string
= NewString (StrPtr
, FormSet
->HiiHandle
);
1674 case EFI_IFR_BITWISE_NOT_OP
:
1676 // Pop an expression from the expression stack
1678 Status
= PopExpression (Value
);
1679 if (EFI_ERROR (Status
)) {
1682 if (Value
->Type
> EFI_IFR_TYPE_DATE
) {
1683 return EFI_INVALID_PARAMETER
;
1686 Value
->Type
= EFI_IFR_TYPE_NUM_SIZE_64
;
1687 Value
->Value
.u64
= ~Value
->Value
.u64
;
1693 case EFI_IFR_ADD_OP
:
1694 case EFI_IFR_SUBTRACT_OP
:
1695 case EFI_IFR_MULTIPLY_OP
:
1696 case EFI_IFR_DIVIDE_OP
:
1697 case EFI_IFR_MODULO_OP
:
1698 case EFI_IFR_BITWISE_AND_OP
:
1699 case EFI_IFR_BITWISE_OR_OP
:
1700 case EFI_IFR_SHIFT_LEFT_OP
:
1701 case EFI_IFR_SHIFT_RIGHT_OP
:
1703 // Pop an expression from the expression stack
1705 Status
= PopExpression (&Data2
);
1706 if (EFI_ERROR (Status
)) {
1709 if (Data2
.Type
> EFI_IFR_TYPE_DATE
) {
1710 return EFI_INVALID_PARAMETER
;
1714 // Pop another expression from the expression stack
1716 Status
= PopExpression (&Data1
);
1717 if (EFI_ERROR (Status
)) {
1720 if (Data1
.Type
> EFI_IFR_TYPE_DATE
) {
1721 return EFI_INVALID_PARAMETER
;
1724 Value
->Type
= EFI_IFR_TYPE_NUM_SIZE_64
;
1726 switch (OpCode
->Operand
) {
1727 case EFI_IFR_ADD_OP
:
1728 Value
->Value
.u64
= Data1
.Value
.u64
+ Data2
.Value
.u64
;
1731 case EFI_IFR_SUBTRACT_OP
:
1732 Value
->Value
.u64
= Data1
.Value
.u64
- Data2
.Value
.u64
;
1735 case EFI_IFR_MULTIPLY_OP
:
1736 Value
->Value
.u64
= MultU64x32 (Data1
.Value
.u64
, (UINT32
) Data2
.Value
.u64
);
1739 case EFI_IFR_DIVIDE_OP
:
1740 Value
->Value
.u64
= DivU64x32 (Data1
.Value
.u64
, (UINT32
) Data2
.Value
.u64
);
1743 case EFI_IFR_MODULO_OP
:
1744 DivU64x32Remainder (Data1
.Value
.u64
, (UINT32
) Data2
.Value
.u64
, &TempValue
);
1745 Value
->Value
.u64
= TempValue
;
1748 case EFI_IFR_BITWISE_AND_OP
:
1749 Value
->Value
.u64
= Data1
.Value
.u64
& Data2
.Value
.u64
;
1752 case EFI_IFR_BITWISE_OR_OP
:
1753 Value
->Value
.u64
= Data1
.Value
.u64
| Data2
.Value
.u64
;
1756 case EFI_IFR_SHIFT_LEFT_OP
:
1757 Value
->Value
.u64
= LShiftU64 (Data1
.Value
.u64
, (UINTN
) Data2
.Value
.u64
);
1760 case EFI_IFR_SHIFT_RIGHT_OP
:
1761 Value
->Value
.u64
= RShiftU64 (Data1
.Value
.u64
, (UINTN
) Data2
.Value
.u64
);
1769 case EFI_IFR_AND_OP
:
1772 // Two Boolean operator
1774 Status
= PopExpression (&Data2
);
1775 if (EFI_ERROR (Status
)) {
1778 if (Data2
.Type
!= EFI_IFR_TYPE_BOOLEAN
) {
1779 return EFI_INVALID_PARAMETER
;
1783 // Pop another expression from the expression stack
1785 Status
= PopExpression (&Data1
);
1786 if (EFI_ERROR (Status
)) {
1789 if (Data1
.Type
!= EFI_IFR_TYPE_BOOLEAN
) {
1790 return EFI_INVALID_PARAMETER
;
1793 if (OpCode
->Operand
== EFI_IFR_AND_OP
) {
1794 Value
->Value
.b
= (BOOLEAN
) (Data1
.Value
.b
&& Data2
.Value
.b
);
1796 Value
->Value
.b
= (BOOLEAN
) (Data1
.Value
.b
|| Data2
.Value
.b
);
1800 case EFI_IFR_EQUAL_OP
:
1801 case EFI_IFR_NOT_EQUAL_OP
:
1802 case EFI_IFR_GREATER_EQUAL_OP
:
1803 case EFI_IFR_GREATER_THAN_OP
:
1804 case EFI_IFR_LESS_EQUAL_OP
:
1805 case EFI_IFR_LESS_THAN_OP
:
1807 // Compare two integer, string, boolean or date/time
1809 Status
= PopExpression (&Data2
);
1810 if (EFI_ERROR (Status
)) {
1813 if (Data2
.Type
> EFI_IFR_TYPE_BOOLEAN
&& Data2
.Type
!= EFI_IFR_TYPE_STRING
) {
1814 return EFI_INVALID_PARAMETER
;
1818 // Pop another expression from the expression stack
1820 Status
= PopExpression (&Data1
);
1821 if (EFI_ERROR (Status
)) {
1825 Result
= CompareHiiValue (&Data1
, &Data2
, FormSet
->HiiHandle
);
1826 if (Result
== EFI_INVALID_PARAMETER
) {
1827 return EFI_INVALID_PARAMETER
;
1830 switch (OpCode
->Operand
) {
1831 case EFI_IFR_EQUAL_OP
:
1832 Value
->Value
.b
= (BOOLEAN
) ((Result
== 0) ? TRUE
: FALSE
);
1835 case EFI_IFR_NOT_EQUAL_OP
:
1836 Value
->Value
.b
= (BOOLEAN
) ((Result
== 0) ? TRUE
: FALSE
);
1839 case EFI_IFR_GREATER_EQUAL_OP
:
1840 Value
->Value
.b
= (BOOLEAN
) ((Result
>= 0) ? TRUE
: FALSE
);
1843 case EFI_IFR_GREATER_THAN_OP
:
1844 Value
->Value
.b
= (BOOLEAN
) ((Result
> 0) ? TRUE
: FALSE
);
1847 case EFI_IFR_LESS_EQUAL_OP
:
1848 Value
->Value
.b
= (BOOLEAN
) ((Result
<= 0) ? TRUE
: FALSE
);
1851 case EFI_IFR_LESS_THAN_OP
:
1852 Value
->Value
.b
= (BOOLEAN
) ((Result
< 0) ? TRUE
: FALSE
);
1860 case EFI_IFR_MATCH_OP
:
1861 Status
= IfrMatch (FormSet
, Value
);
1864 case EFI_IFR_CATENATE_OP
:
1865 Status
= IfrCatenate (FormSet
, Value
);
1871 case EFI_IFR_CONDITIONAL_OP
:
1873 // Pop third expression from the expression stack
1875 Status
= PopExpression (&Data3
);
1876 if (EFI_ERROR (Status
)) {
1881 // Pop second expression from the expression stack
1883 Status
= PopExpression (&Data2
);
1884 if (EFI_ERROR (Status
)) {
1889 // Pop first expression from the expression stack
1891 Status
= PopExpression (&Data1
);
1892 if (EFI_ERROR (Status
)) {
1895 if (Data1
.Type
!= EFI_IFR_TYPE_BOOLEAN
) {
1896 return EFI_INVALID_PARAMETER
;
1899 if (Data1
.Value
.b
) {
1906 case EFI_IFR_FIND_OP
:
1907 Status
= IfrFind (FormSet
, OpCode
->Format
, Value
);
1910 case EFI_IFR_MID_OP
:
1911 Status
= IfrMid (FormSet
, Value
);
1914 case EFI_IFR_TOKEN_OP
:
1915 Status
= IfrToken (FormSet
, Value
);
1918 case EFI_IFR_SPAN_OP
:
1919 Status
= IfrSpan (FormSet
, OpCode
->Flags
, Value
);
1925 if (EFI_ERROR (Status
)) {
1929 Status
= PushExpression (Value
);
1930 if (EFI_ERROR (Status
)) {
1936 // Pop the final result from expression stack
1939 Status
= PopExpression (Value
);
1940 if (EFI_ERROR (Status
)) {
1945 // After evaluating an expression, there should be only one value left on the expression stack
1947 if (PopExpression (Value
) != EFI_ACCESS_DENIED
) {
1948 return EFI_INVALID_PARAMETER
;
1951 CopyMem (&Expression
->Result
, Value
, sizeof (EFI_HII_VALUE
));