]> git.proxmox.com Git - mirror_edk2.git/blame - IntelFrameworkModulePkg/Universal/SetupBrowserDxe/Boolean.c
Modules clean up.
[mirror_edk2.git] / IntelFrameworkModulePkg / Universal / SetupBrowserDxe / Boolean.c
CommitLineData
103b6520 1/*++\r
2\r
3Copyright (c) 2006 - 2007, Intel Corporation\r
4All rights reserved. This program and the accompanying materials\r
5are licensed and made available under the terms and conditions of the BSD License\r
6which accompanies this distribution. The full text of the license may be found at\r
7http://opensource.org/licenses/bsd-license.php\r
8\r
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
11\r
12Module Name:\r
13\r
14 Boolean.c\r
15\r
16Abstract:\r
17\r
18 This routine will evaluate the IFR inconsistency data to determine if\r
19 something is a valid entry for a particular expression\r
20\r
21--*/\r
22\r
103b6520 23\r
24#include "Setup.h"\r
25#include "Ui.h"\r
26\r
27//\r
28// Global stack used to evaluate boolean expresions\r
29//\r
30BOOLEAN *mBooleanEvaluationStack = (BOOLEAN) 0;\r
31BOOLEAN *mBooleanEvaluationStackEnd = (BOOLEAN) 0;\r
32\r
33STATIC\r
34VOID\r
35GrowBooleanStack (\r
36 IN OUT BOOLEAN **Stack,\r
37 IN UINTN StackSizeInBoolean\r
38 )\r
39/*++\r
40\r
41Routine Description:\r
42\r
43 Grow size of the boolean stack\r
44\r
45Arguments:\r
46\r
47 Stack - Old stack on the way in and new stack on the way out\r
48\r
49 StackSizeInBoolean - New size of the stack\r
50\r
51Returns:\r
52\r
53 NONE\r
54\r
55--*/\r
56{\r
57 BOOLEAN *NewStack;\r
58\r
59 NewStack = AllocatePool (StackSizeInBoolean * sizeof (BOOLEAN));\r
60 ASSERT (NewStack != NULL);\r
61\r
62 if (*Stack != NULL) {\r
63 //\r
64 // Copy to Old Stack to the New Stack\r
65 //\r
66 CopyMem (\r
67 NewStack,\r
68 mBooleanEvaluationStack,\r
69 (mBooleanEvaluationStackEnd - mBooleanEvaluationStack) * sizeof (BOOLEAN)\r
70 );\r
71\r
72 //\r
73 // Make the Stack pointer point to the old data in the new stack\r
74 //\r
75 *Stack = NewStack + (*Stack - mBooleanEvaluationStack);\r
76\r
77 //\r
78 // Free The Old Stack\r
79 //\r
80 FreePool (mBooleanEvaluationStack);\r
81 }\r
82\r
83 mBooleanEvaluationStack = NewStack;\r
84 mBooleanEvaluationStackEnd = NewStack + StackSizeInBoolean;\r
85}\r
86\r
87STATIC\r
88VOID\r
89InitializeBooleanEvaluator (\r
90 VOID\r
91 )\r
92/*++\r
93\r
94Routine Description:\r
95\r
96 Allocate a global stack for boolean processing.\r
97\r
98Arguments:\r
99\r
100 NONE\r
101\r
102Returns:\r
103\r
104 NONE\r
105\r
106--*/\r
107{\r
108 BOOLEAN *NullStack;\r
109\r
110 NullStack = NULL;\r
111 GrowBooleanStack (&NullStack, 0x1000);\r
112}\r
113\r
114STATIC\r
115VOID\r
116PushBool (\r
117 IN OUT BOOLEAN **Stack,\r
118 IN BOOLEAN BoolResult\r
119 )\r
120/*++\r
121\r
122Routine Description:\r
123\r
124 Push an element onto the Boolean Stack\r
125\r
126Arguments:\r
127\r
128 Stack - Current stack location.\r
129 BoolResult - BOOLEAN to push.\r
130\r
131Returns:\r
132\r
133 None.\r
134\r
135--*/\r
136{\r
137 CopyMem (*Stack, &BoolResult, sizeof (BOOLEAN));\r
138 *Stack += 1;\r
139\r
140 if (*Stack >= mBooleanEvaluationStackEnd) {\r
141 //\r
142 // If we run out of stack space make a new one that is 2X as big. Copy\r
143 // the old data into the new stack and update Stack to point to the old\r
144 // data in the new stack.\r
145 //\r
146 GrowBooleanStack (\r
147 Stack,\r
148 (mBooleanEvaluationStackEnd - mBooleanEvaluationStack) * sizeof (BOOLEAN) * 2\r
149 );\r
150 }\r
151}\r
152\r
153STATIC\r
154BOOLEAN\r
155PopBool (\r
156 IN OUT BOOLEAN **Stack\r
157 )\r
158/*++\r
159\r
160Routine Description:\r
161\r
162 Pop an element from the Boolean stack.\r
163\r
164Arguments:\r
165\r
166 Stack - Current stack location\r
167\r
168Returns:\r
169\r
170 Top of the BOOLEAN stack.\r
171\r
172--*/\r
173{\r
174 BOOLEAN ReturnValue;\r
175\r
176 *Stack -= 1;\r
177 CopyMem (&ReturnValue, *Stack, sizeof (BOOLEAN));\r
178 return ReturnValue;\r
179}\r
180\r
181STATIC\r
182EFI_STATUS\r
183GrowBooleanExpression (\r
184 IN EFI_INCONSISTENCY_DATA *InconsistentTags,\r
185 OUT VOID **BooleanExpression,\r
186 IN OUT UINTN *BooleanExpressionLength\r
187 )\r
188{\r
189 UINT8 *NewExpression;\r
190\r
191 NewExpression = AllocatePool (*BooleanExpressionLength + sizeof (EFI_INCONSISTENCY_DATA));\r
192 ASSERT (NewExpression != NULL);\r
193\r
194 if (*BooleanExpression != NULL) {\r
195 //\r
196 // Copy Old buffer to the New buffer\r
197 //\r
198 CopyMem (NewExpression, *BooleanExpression, *BooleanExpressionLength);\r
199\r
200 CopyMem (&NewExpression[*BooleanExpressionLength], InconsistentTags, sizeof (EFI_INCONSISTENCY_DATA));\r
201\r
202 //\r
203 // Free The Old buffer\r
204 //\r
205 FreePool (*BooleanExpression);\r
206 } else {\r
207 //\r
208 // Copy data into new buffer\r
209 //\r
210 CopyMem (NewExpression, InconsistentTags, sizeof (EFI_INCONSISTENCY_DATA));\r
211 }\r
212\r
213 *BooleanExpressionLength = *BooleanExpressionLength + sizeof (EFI_INCONSISTENCY_DATA);\r
214 *BooleanExpression = (VOID *) NewExpression;\r
215 return EFI_SUCCESS;\r
216}\r
217\r
218STATIC\r
219VOID\r
220CreateBooleanExpression (\r
221 IN EFI_FILE_FORM_TAGS *FileFormTags,\r
222 IN UINT16 Value,\r
223 IN UINT16 Id,\r
224 IN BOOLEAN Complex,\r
225 OUT VOID **BooleanExpression,\r
226 OUT UINTN *BooleanExpressionLength\r
227 )\r
228/*++\r
229\r
230Routine Description:\r
231\r
232Arguments:\r
233\r
234Returns:\r
235\r
236--*/\r
237{\r
238 UINTN Count;\r
239 EFI_INCONSISTENCY_DATA *InconsistentTags;\r
240 EFI_INCONSISTENCY_DATA FakeInconsistentTags;\r
241\r
242 InconsistentTags = FileFormTags->InconsistentTags;\r
243\r
244 //\r
245 // Did we run into a question that contains the Id we are looking for?\r
246 //\r
247 for (Count = 0; InconsistentTags->Operand != 0xFF; Count++) {\r
248\r
249 //\r
250 // Reserve INVALID_OFFSET_VALUE - 1 for TURE and FALSE, because we need to treat them as well\r
251 // as ideqid etc. but they have no coresponding id, so we reserve this value.\r
252 //\r
253 if (InconsistentTags->QuestionId1 == Id ||\r
254 InconsistentTags->QuestionId1 == INVALID_OFFSET_VALUE - 1) {\r
255 //\r
256 // If !Complex - means evaluate a single if/endif expression\r
257 //\r
258 if (!Complex) {\r
259 //\r
260 // If the ConsistencyId does not match the expression we are looking for\r
261 // skip to the next consistency database entry\r
262 //\r
263 if (InconsistentTags->ConsistencyId != Value) {\r
264 goto NextEntry;\r
265 }\r
266 }\r
267 //\r
268 // We need to rewind to the beginning of the Inconsistent expression\r
269 //\r
270 for (;\r
271 (InconsistentTags->Operand != EFI_IFR_INCONSISTENT_IF_OP) &&\r
272 (InconsistentTags->Operand != EFI_IFR_GRAYOUT_IF_OP) &&\r
273 (InconsistentTags->Operand != EFI_IFR_SUPPRESS_IF_OP);\r
274 ) {\r
275 InconsistentTags = InconsistentTags->Previous;\r
276 }\r
277 //\r
278 // Store the consistency check expression, ensure the next for loop starts at the op-code afterwards\r
279 //\r
280 GrowBooleanExpression (InconsistentTags, BooleanExpression, BooleanExpressionLength);\r
281 InconsistentTags = InconsistentTags->Next;\r
282\r
283 //\r
284 // Keep growing until we hit the End expression op-code or we hit the beginning of another\r
285 // consistency check like grayout/suppress\r
286 //\r
287 for (;\r
288 InconsistentTags->Operand != EFI_IFR_END_IF_OP &&\r
289 InconsistentTags->Operand != EFI_IFR_GRAYOUT_IF_OP &&\r
290 InconsistentTags->Operand != EFI_IFR_SUPPRESS_IF_OP;\r
291 ) {\r
292 GrowBooleanExpression (InconsistentTags, BooleanExpression, BooleanExpressionLength);\r
293 InconsistentTags = InconsistentTags->Next;\r
294 }\r
295 //\r
296 // Store the EndExpression Op-code\r
297 //\r
298 GrowBooleanExpression (InconsistentTags, BooleanExpression, BooleanExpressionLength);\r
299 }\r
300\r
301NextEntry:\r
302 if (InconsistentTags->Next != NULL) {\r
303 //\r
304 // Skip to next entry\r
305 //\r
306 InconsistentTags = InconsistentTags->Next;\r
307 }\r
308 }\r
309\r
310 FakeInconsistentTags.Operand = 0;\r
311\r
312 //\r
313 // Add one last expression which will signify we have definitely hit the end\r
314 //\r
315 GrowBooleanExpression (&FakeInconsistentTags, BooleanExpression, BooleanExpressionLength);\r
316}\r
317\r
318STATIC\r
319EFI_STATUS\r
320BooleanVariableWorker (\r
321 IN CHAR16 *VariableName,\r
322 IN EFI_VARIABLE_DEFINITION *VariableDefinition,\r
323 IN BOOLEAN *StackPtr,\r
324 IN OUT UINTN *SizeOfVariable,\r
325 IN OUT VOID **VariableData\r
326 )\r
327/*++\r
328\r
329Routine Description:\r
330\r
331\r
332Arguments:\r
333\r
334Returns:\r
335\r
336--*/\r
337{\r
338 EFI_STATUS Status;\r
339\r
340 Status = gRT->GetVariable (\r
341 VariableName,\r
342 &VariableDefinition->Guid,\r
343 NULL,\r
344 SizeOfVariable,\r
345 *VariableData\r
346 );\r
347\r
348 if (EFI_ERROR (Status)) {\r
349\r
350 if (Status == EFI_BUFFER_TOO_SMALL) {\r
351 *VariableData = AllocatePool (*SizeOfVariable);\r
352 ASSERT (*VariableData != NULL);\r
353\r
354 Status = gRT->GetVariable (\r
355 VariableName,\r
356 &VariableDefinition->Guid,\r
357 NULL,\r
358 SizeOfVariable,\r
359 *VariableData\r
360 );\r
361 }\r
362\r
363 if (Status == EFI_NOT_FOUND) {\r
364 //\r
365 // This is a serious flaw, we must have some standard result if a variable\r
366 // is not found. Our default behavior must either be return a TRUE or FALSE\r
367 // since there is nothing else we can really do. Therefore, my crystal ball\r
368 // says I will return a FALSE\r
369 //\r
370 PushBool (&StackPtr, FALSE);\r
371 }\r
372 }\r
373\r
374 return Status;\r
375}\r
376\r
377STATIC\r
378UINT8\r
379PredicateIfrType (\r
380 IN EFI_INCONSISTENCY_DATA *Iterator\r
381 )\r
382/*++\r
383\r
384Routine Description:\r
385 This routine is for the purpose of predicate whether the Ifr is generated by a VfrCompiler greater than or equal to 1.88 or\r
386 less than 1.88 which is legacy.\r
387\r
388Arguments:\r
389 Iterator - The pointer to inconsistency tags\r
390\r
391Returns:\r
392\r
393 0x2 - If IFR is not legacy\r
394\r
395 0x1 - If IFR is legacy\r
396\r
397--*/\r
398{\r
399 //\r
400 // legacy Ifr cover the states:\r
401 // Not ...\r
402 // Operand Opcode Operand\r
403 //\r
404 // while Operand means ideqval, TRUE, or other what can be evaluated to True or False,\r
405 // and Opcode means AND or OR.\r
406 //\r
407 if (Iterator->Operand == EFI_IFR_NOT_OP ||\r
408 Iterator->Operand == 0) {\r
409 return 0x1;\r
410 } else if (Iterator->Operand == EFI_IFR_EQ_VAR_VAL_OP ||\r
411 Iterator->Operand == EFI_IFR_EQ_ID_VAL_OP ||\r
412 Iterator->Operand == EFI_IFR_EQ_ID_ID_OP ||\r
413 Iterator->Operand == EFI_IFR_EQ_ID_LIST_OP) {\r
414 Iterator++;\r
415 if (Iterator->Operand == EFI_IFR_AND_OP ||\r
416 Iterator->Operand == EFI_IFR_OR_OP) {\r
417 Iterator--;\r
418 return 0x1;\r
419 }\r
420 Iterator--;\r
421 }\r
422 return 0x2;\r
423}\r
424\r
425STATIC\r
426VOID\r
427PostOrderEvaluate (\r
428 IN EFI_FILE_FORM_TAGS *FileFormTags,\r
429 IN UINT16 Width,\r
430 IN OUT EFI_INCONSISTENCY_DATA **PIterator,\r
431 IN OUT BOOLEAN **StackPtr\r
432 )\r
433/*++\r
434\r
435Routine Description:\r
436 PostOrderEvaluate is used for Ifr generated by VfrCompiler greater than or equal to 1.88,\r
437 which generate Operand Operand Opcode type Ifr.\r
438 PostOrderEvaluete only evaluate boolean expression part, not suppressif/grayoutif. TRUE,\r
439 FALSE, >=, >, (, ) are supported.\r
440\r
441Arguments:\r
442\r
443 FileFormTags - The pointer to the tags of the form\r
444\r
445 Width - Width of Operand, recognized every iteration\r
446\r
447 PIterator - The pointer to inconsistency tags\r
448\r
449 StackPtr - The pointer to the evaluation stack\r
450\r
451Returns:\r
452\r
453 TRUE - If value is valid\r
454\r
455 FALSE - If value is not valid\r
456\r
457--*/\r
458{\r
459 BOOLEAN Operator;\r
460 BOOLEAN Operator2;\r
461 UINT16 *MapBuffer;\r
462 UINT16 *MapBuffer2;\r
463 UINT16 MapValue;\r
464 UINT16 MapValue2;\r
465 UINTN SizeOfVariable;\r
466 CHAR16 VariableName[MAXIMUM_VALUE_CHARACTERS];\r
467 VOID *VariableData;\r
468 EFI_VARIABLE_DEFINITION *VariableDefinition;\r
469 EFI_STATUS Status;\r
470 UINTN Index;\r
471 BOOLEAN PushValue;\r
472\r
473 Operator = FALSE;\r
474 Operator2 = FALSE;\r
475 MapBuffer = NULL;\r
476 MapBuffer2 = NULL;\r
477 MapValue = 0;\r
478 MapValue2 = 0;\r
479 VariableData = NULL;\r
480\r
481 while (TRUE) {\r
482 if ((*PIterator)->Operand == 0) {\r
483 return;\r
484 }\r
485\r
486 Width = (*PIterator)->Width;\r
487\r
488 //\r
489 // Because INVALID_OFFSET_VALUE - 1 is reserved for TRUE or FALSE, omit them.\r
490 //\r
491 if ((*PIterator)->QuestionId1 != INVALID_OFFSET_VALUE &&\r
492 (*PIterator)->QuestionId1 != INVALID_OFFSET_VALUE - 1) {\r
493 ExtractNvValue (FileFormTags, (*PIterator)->VariableNumber, Width, (*PIterator)->QuestionId1, (VOID **) &MapBuffer);\r
494 ExtractNvValue (FileFormTags, (*PIterator)->VariableNumber2, Width, (*PIterator)->QuestionId2, (VOID **) &MapBuffer2);\r
495 if (MapBuffer != NULL) {\r
496 if (Width == 2) {\r
497 MapValue = *MapBuffer;\r
498 } else {\r
499 MapValue = (UINT8) *MapBuffer;\r
500 }\r
501\r
502 FreePool (MapBuffer);\r
503 }\r
504\r
505 if (MapBuffer2 != NULL) {\r
506 if (Width == 2) {\r
507 MapValue2 = *MapBuffer2;\r
508 } else {\r
509 MapValue2 = (UINT8) *MapBuffer2;\r
510 }\r
511\r
512 FreePool (MapBuffer2);\r
513 }\r
514 }\r
515\r
516 switch ((*PIterator)->Operand) {\r
517 case EFI_IFR_EQ_VAR_VAL_OP:\r
518 UnicodeValueToString (\r
519 VariableName,\r
520 FALSE,\r
521 (UINTN) (*PIterator)->QuestionId1,\r
522 (sizeof (VariableName) / sizeof (VariableName[0])) - 1\r
523 );\r
524\r
525 SizeOfVariable = 0;\r
526\r
527 ExtractRequestedNvMap (FileFormTags, (*PIterator)->VariableNumber, &VariableDefinition);\r
528\r
529 Status = BooleanVariableWorker (\r
530 VariableName,\r
531 VariableDefinition,\r
532 *StackPtr,\r
533 &SizeOfVariable,\r
534 &VariableData\r
535 );\r
536\r
537 if (!EFI_ERROR (Status)) {\r
538 if (SizeOfVariable == 1) {\r
539 CopyMem (&MapValue, VariableData, 1);\r
540 } else {\r
541 CopyMem (&MapValue, VariableData, 2);\r
542 }\r
543\r
544 //\r
545 // Do operation after knowing the compare operator.\r
546 //\r
547 MapValue2 = (*PIterator)->Value;\r
548 (*PIterator)++;\r
549 if ((*PIterator)->Operand == EFI_IFR_GT_OP) {\r
550 PushValue = (BOOLEAN) (MapValue > MapValue2);\r
551 } else if ((*PIterator)->Operand == EFI_IFR_GE_OP) {\r
552 PushValue = (BOOLEAN) (MapValue >= MapValue2);\r
553 } else {\r
554 (*PIterator)--;\r
555 PushValue = (BOOLEAN) (MapValue == MapValue2);\r
556 }\r
557 PushBool (StackPtr, PushValue);\r
558 }\r
559\r
560 break;\r
561\r
562 case EFI_IFR_EQ_ID_VAL_OP:\r
563 //\r
564 // Do operation after knowing the compare operator.\r
565 //\r
566 MapValue2 = (*PIterator)->Value;\r
567 (*PIterator)++;\r
568 if ((*PIterator)->Operand == EFI_IFR_GT_OP) {\r
569 PushValue = (BOOLEAN) (MapValue > MapValue2);\r
570 } else if ((*PIterator)->Operand == EFI_IFR_GE_OP) {\r
571 PushValue = (BOOLEAN) (MapValue >= MapValue2);\r
572 } else {\r
573 (*PIterator)--;\r
574 PushValue = (BOOLEAN) (MapValue == MapValue2);\r
575 }\r
576 PushBool (StackPtr, PushValue);\r
577 break;\r
578\r
579 case EFI_IFR_EQ_ID_ID_OP:\r
580 //\r
581 // Do operation after knowing the compare operator.\r
582 //\r
583 (*PIterator)++;\r
584 if ((*PIterator)->Operand == EFI_IFR_GT_OP) {\r
585 PushValue = (BOOLEAN) (MapValue > MapValue2);\r
586 } else if ((*PIterator)->Operand == EFI_IFR_GE_OP) {\r
587 PushValue = (BOOLEAN) (MapValue >= MapValue2);\r
588 } else {\r
589 (*PIterator)--;\r
590 PushValue = (BOOLEAN) (MapValue == MapValue2);\r
591 }\r
592 PushBool (StackPtr, PushValue);\r
593 break;\r
594\r
595 case EFI_IFR_EQ_ID_LIST_OP:\r
596 for (Index = 0; Index < (*PIterator)->ListLength; Index++) {\r
597 Operator = (BOOLEAN) (MapValue == (*PIterator)->ValueList[Index]);\r
598 if (Operator) {\r
599 break;\r
600 }\r
601 }\r
602\r
603 PushBool (StackPtr, Operator);\r
604 break;\r
605\r
606 case EFI_IFR_TRUE_OP:\r
607 PushBool (StackPtr, TRUE);\r
608 break;\r
609\r
610 case EFI_IFR_FALSE_OP:\r
611 PushBool (StackPtr, FALSE);\r
612 break;\r
613\r
614 case EFI_IFR_AND_OP:\r
615 Operator = PopBool (StackPtr);\r
616 Operator2 = PopBool (StackPtr);\r
617 PushBool (StackPtr, (BOOLEAN) (Operator && Operator2));\r
618 break;\r
619 case EFI_IFR_OR_OP:\r
620 Operator = PopBool (StackPtr);\r
621 Operator2 = PopBool (StackPtr);\r
622 PushBool (StackPtr, (BOOLEAN) (Operator || Operator2));\r
623 break;\r
624 case EFI_IFR_NOT_OP:\r
625 Operator = PopBool (StackPtr);\r
626 PushBool (StackPtr, (BOOLEAN) (!Operator));\r
627 break;\r
628\r
629 case EFI_IFR_SUPPRESS_IF_OP:\r
630 case EFI_IFR_GRAYOUT_IF_OP:\r
631 case EFI_IFR_INCONSISTENT_IF_OP:\r
632 default:\r
633 //\r
634 // Return to the previous tag if runs out of boolean expression.\r
635 //\r
636 (*PIterator)--;\r
637 return;\r
638 }\r
639 (*PIterator)++;\r
640 }\r
641}\r
642\r
643BOOLEAN\r
644ValueIsNotValid (\r
645 IN BOOLEAN Complex,\r
646 IN UINT16 Value,\r
647 IN EFI_TAG *Tag,\r
648 IN EFI_FILE_FORM_TAGS *FileFormTags,\r
649 IN STRING_REF *PopUp\r
650 )\r
651/*++\r
652\r
653Routine Description:\r
654\r
655\r
656Arguments:\r
657\r
658Returns:\r
659\r
660 TRUE - If value is valid\r
661\r
662 FALSE - If value is not valid\r
663\r
664--*/\r
665{\r
666 BOOLEAN *StackPtr;\r
667 EFI_INCONSISTENCY_DATA *Iterator;\r
668 BOOLEAN Operator;\r
669 BOOLEAN Operator2;\r
670 UINTN Index;\r
671 VOID *BooleanExpression;\r
672 UINTN BooleanExpressionLength;\r
673 BOOLEAN NotOperator;\r
674 BOOLEAN OrOperator;\r
675 BOOLEAN AndOperator;\r
676 BOOLEAN ArtificialEnd;\r
677 UINT16 *MapBuffer;\r
678 UINT16 *MapBuffer2;\r
679 UINT16 MapValue;\r
680 UINT16 MapValue2;\r
681 UINTN SizeOfVariable;\r
682 CHAR16 VariableName[MAXIMUM_VALUE_CHARACTERS];\r
683 VOID *VariableData;\r
684 EFI_STATUS Status;\r
685 UINT16 Id;\r
686 UINT16 Width;\r
687 EFI_VARIABLE_DEFINITION *VariableDefinition;\r
688 BOOLEAN CosmeticConsistency;\r
689 UINT8 IsLegacy;\r
690\r
691 VariableData = NULL;\r
692 BooleanExpressionLength = 0;\r
693 BooleanExpression = NULL;\r
694 Operator = FALSE;\r
695 ArtificialEnd = FALSE;\r
696 CosmeticConsistency = TRUE;\r
697 IsLegacy = 0;\r
698\r
699 Id = Tag->Id;\r
700 if (Tag->StorageWidth == 1) {\r
701 Width = 1;\r
702 } else {\r
703 Width = 2;\r
704 }\r
705 CreateBooleanExpression (FileFormTags, Value, Id, Complex, &BooleanExpression, &BooleanExpressionLength);\r
706\r
707 if (mBooleanEvaluationStack == 0) {\r
708 InitializeBooleanEvaluator ();\r
709 }\r
710\r
711 if (BooleanExpression == NULL) {\r
712 return FALSE;\r
713 }\r
714\r
715 StackPtr = mBooleanEvaluationStack;\r
716 Iterator = BooleanExpression;\r
717 MapBuffer = NULL;\r
718 MapBuffer2 = NULL;\r
719 MapValue = 0;\r
720 MapValue2 = 0;\r
721\r
722 while (TRUE) {\r
723 NotOperator = FALSE;\r
724 OrOperator = FALSE;\r
725 AndOperator = FALSE;\r
726\r
727 if (Iterator->Operand == 0) {\r
728 return Operator;\r
729 }\r
730\r
731 //\r
732 // Because INVALID_OFFSET_VALUE - 1 is reserved for TRUE or FALSE, omit them.\r
733 //\r
734 if (Iterator->QuestionId1 != INVALID_OFFSET_VALUE &&\r
735 Iterator->QuestionId1 != INVALID_OFFSET_VALUE-1) {\r
736 ExtractNvValue (FileFormTags, Iterator->VariableNumber, Width, Iterator->QuestionId1, (VOID **) &MapBuffer);\r
737 ExtractNvValue (FileFormTags, Iterator->VariableNumber2, Width, Iterator->QuestionId2, (VOID **) &MapBuffer2);\r
738 if (MapBuffer != NULL) {\r
739 if (Width == 2) {\r
740 MapValue = *MapBuffer;\r
741 } else {\r
742 MapValue = (UINT8) *MapBuffer;\r
743 }\r
744\r
745 FreePool (MapBuffer);\r
746 }\r
747\r
748 if (MapBuffer2 != NULL) {\r
749 if (Width == 2) {\r
750 MapValue2 = *MapBuffer2;\r
751 } else {\r
752 MapValue2 = (UINT8) *MapBuffer2;\r
753 }\r
754\r
755 FreePool (MapBuffer2);\r
756 }\r
757 }\r
758\r
759 switch (Iterator->Operand) {\r
760 case EFI_IFR_SUPPRESS_IF_OP:\r
761 //\r
762 // Must have hit a suppress followed by a grayout or vice-versa\r
763 //\r
764 if (ArtificialEnd) {\r
765 ArtificialEnd = FALSE;\r
766 Operator = PopBool (&StackPtr);\r
767 if (Operator) {\r
768 Tag->Suppress = TRUE;\r
769 }\r
770\r
771 return Operator;\r
772 }\r
773\r
774 ArtificialEnd = TRUE;\r
775 *PopUp = Iterator->Popup;\r
776 break;\r
777\r
778 case EFI_IFR_GRAYOUT_IF_OP:\r
779 //\r
780 // Must have hit a suppress followed by a grayout or vice-versa\r
781 //\r
782 if (ArtificialEnd) {\r
783 ArtificialEnd = FALSE;\r
784 Operator = PopBool (&StackPtr);\r
785 if (Operator) {\r
786 Tag->GrayOut = TRUE;\r
787 }\r
788\r
789 return Operator;\r
790 }\r
791\r
792 ArtificialEnd = TRUE;\r
793 *PopUp = Iterator->Popup;\r
794 break;\r
795\r
796 case EFI_IFR_INCONSISTENT_IF_OP:\r
797 CosmeticConsistency = FALSE;\r
798 *PopUp = Iterator->Popup;\r
799 break;\r
800\r
801 //\r
802 // In the case of external variable values, we must read the variable which is\r
803 // named by the human readable version of the OpCode->VariableId and the guid of the formset\r
804 //\r
805 case EFI_IFR_EQ_VAR_VAL_OP:\r
806 //\r
807 // To check whether Ifr is legacy. Once every boolean expression.\r
808 //\r
809 if (IsLegacy == 0) {\r
810 IsLegacy = PredicateIfrType (Iterator);\r
811 }\r
812 if (IsLegacy == 0x2) {\r
813 PostOrderEvaluate (FileFormTags, Width, &Iterator, &StackPtr);\r
814 break;\r
815 }\r
816\r
817 UnicodeValueToString (\r
818 VariableName,\r
819 FALSE,\r
820 (UINTN) Iterator->QuestionId1,\r
821 (sizeof (VariableName) / sizeof (VariableName[0])) - 1\r
822 );\r
823\r
824 SizeOfVariable = 0;\r
825\r
826 ExtractRequestedNvMap (FileFormTags, Iterator->VariableNumber, &VariableDefinition);\r
827\r
828 Status = BooleanVariableWorker (\r
829 VariableName,\r
830 VariableDefinition,\r
831 StackPtr,\r
832 &SizeOfVariable,\r
833 &VariableData\r
834 );\r
835\r
836 if (!EFI_ERROR (Status)) {\r
837 if (SizeOfVariable == 1) {\r
838 CopyMem (&MapValue, VariableData, 1);\r
839 } else {\r
840 CopyMem (&MapValue, VariableData, 2);\r
841 }\r
842\r
843 PushBool (&StackPtr, (BOOLEAN) (MapValue == Iterator->Value));\r
844 }\r
845\r
846 break;\r
847\r
848 case EFI_IFR_EQ_ID_VAL_OP:\r
849 //\r
850 // To check whether Ifr is legacy. Once every boolean expression.\r
851 //\r
852 if (IsLegacy == 0) {\r
853 IsLegacy = PredicateIfrType (Iterator);\r
854 }\r
855 if (IsLegacy == 0x2) {\r
856 PostOrderEvaluate (FileFormTags, Width, &Iterator, &StackPtr);\r
857 break;\r
858 }\r
859\r
860 PushBool (&StackPtr, (BOOLEAN) (MapValue == Iterator->Value));\r
861 break;\r
862\r
863 case EFI_IFR_EQ_ID_ID_OP:\r
864 //\r
865 // To check whether Ifr is legacy. Once every boolean expression.\r
866 //\r
867 if (IsLegacy == 0) {\r
868 IsLegacy = PredicateIfrType (Iterator);\r
869 }\r
870 if (IsLegacy == 0x2) {\r
871 PostOrderEvaluate (FileFormTags, Width, &Iterator, &StackPtr);\r
872 break;\r
873 }\r
874\r
875 PushBool (&StackPtr, (BOOLEAN) (MapValue == MapValue2));\r
876 break;\r
877\r
878 case EFI_IFR_EQ_ID_LIST_OP:\r
879 //\r
880 // To check whether Ifr is legacy. Once every boolean expression.\r
881 //\r
882 if (IsLegacy == 0) {\r
883 IsLegacy = PredicateIfrType (Iterator);\r
884 }\r
885 if (IsLegacy == 0x2) {\r
886 PostOrderEvaluate (FileFormTags, Width, &Iterator, &StackPtr);\r
887 break;\r
888 }\r
889\r
890 for (Index = 0; Index < Iterator->ListLength; Index++) {\r
891 Operator = (BOOLEAN) (MapValue == Iterator->ValueList[Index]);\r
892 if (Operator) {\r
893 break;\r
894 }\r
895 }\r
896\r
897 PushBool (&StackPtr, Operator);\r
898 break;\r
899\r
900 case EFI_IFR_AND_OP:\r
901 Iterator++;\r
902 if (Iterator->Operand == EFI_IFR_NOT_OP) {\r
903 NotOperator = TRUE;\r
904 Iterator++;\r
905 }\r
906\r
907 if (Iterator->QuestionId1 != INVALID_OFFSET_VALUE) {\r
908 ExtractNvValue (FileFormTags, Iterator->VariableNumber, Width, Iterator->QuestionId1, (VOID **) &MapBuffer);\r
909 ExtractNvValue (FileFormTags, Iterator->VariableNumber2, Width, Iterator->QuestionId2, (VOID **) &MapBuffer2);\r
910 if (MapBuffer != NULL) {\r
911 if (Width == 2) {\r
912 MapValue = *MapBuffer;\r
913 } else {\r
914 MapValue = (UINT8) *MapBuffer;\r
915 }\r
916\r
917 FreePool (MapBuffer);\r
918 }\r
919\r
920 if (MapBuffer2 != NULL) {\r
921 if (Width == 2) {\r
922 MapValue2 = *MapBuffer2;\r
923 } else {\r
924 MapValue2 = (UINT8) *MapBuffer2;\r
925 }\r
926\r
927 FreePool (MapBuffer2);\r
928 }\r
929 }\r
930\r
931 switch (Iterator->Operand) {\r
932 case EFI_IFR_EQ_ID_VAL_OP:\r
933 //\r
934 // If Not - flip the results\r
935 //\r
936 if (NotOperator) {\r
937 Operator = (BOOLEAN)!(MapValue == Iterator->Value);\r
938 } else {\r
939 Operator = (BOOLEAN) (MapValue == Iterator->Value);\r
940 }\r
941\r
942 PushBool (&StackPtr, Operator);\r
943 break;\r
944\r
945 //\r
946 // In the case of external variable values, we must read the variable which is\r
947 // named by the human readable version of the OpCode->VariableId and the guid of the formset\r
948 //\r
949 case EFI_IFR_EQ_VAR_VAL_OP:\r
950 UnicodeValueToString (\r
951 VariableName,\r
952 FALSE,\r
953 (UINTN) Iterator->QuestionId1,\r
954 (sizeof (VariableName) / sizeof (VariableName[0])) - 1\r
955 );\r
956\r
957 SizeOfVariable = 0;\r
958\r
959 ExtractRequestedNvMap (FileFormTags, Iterator->VariableNumber, &VariableDefinition);\r
960\r
961 Status = BooleanVariableWorker (\r
962 VariableName,\r
963 VariableDefinition,\r
964 StackPtr,\r
965 &SizeOfVariable,\r
966 &VariableData\r
967 );\r
968\r
969 if (!EFI_ERROR (Status)) {\r
970 if (SizeOfVariable == 1) {\r
971 CopyMem (&MapValue, VariableData, 1);\r
972 } else {\r
973 CopyMem (&MapValue, VariableData, 2);\r
974 }\r
975 //\r
976 // If Not - flip the results\r
977 //\r
978 if (NotOperator) {\r
979 PushBool (&StackPtr, (BOOLEAN)!(MapValue == Iterator->Value));\r
980 } else {\r
981 PushBool (&StackPtr, (BOOLEAN) (MapValue == Iterator->Value));\r
982 }\r
983 }\r
984 break;\r
985\r
986 case EFI_IFR_EQ_ID_ID_OP:\r
987 //\r
988 // If Not - flip the results\r
989 //\r
990 if (NotOperator) {\r
991 Operator = (BOOLEAN)!(MapValue == MapValue2);\r
992 } else {\r
993 Operator = (BOOLEAN) (MapValue == MapValue2);\r
994 }\r
995\r
996 PushBool (&StackPtr, Operator);\r
997 break;\r
998\r
999 case EFI_IFR_EQ_ID_LIST_OP:\r
1000 for (Index = 0; Index < Iterator->ListLength; Index++) {\r
1001 //\r
1002 // If Not - flip the results\r
1003 //\r
1004 if (NotOperator) {\r
1005 Operator = (BOOLEAN)!(MapValue == Iterator->ValueList[Index]);\r
1006 } else {\r
1007 Operator = (BOOLEAN) (MapValue == Iterator->ValueList[Index]);\r
1008 }\r
1009 //\r
1010 // If We are trying to make sure that MapValue != Item[x], keep looking through\r
1011 // the list to make sure we don't equal any other items\r
1012 //\r
1013 if (Operator && NotOperator) {\r
1014 continue;\r
1015 }\r
1016 //\r
1017 // If MapValue == Item, then we have succeeded (first found is good enough)\r
1018 //\r
1019 if (Operator) {\r
1020 break;\r
1021 }\r
1022 }\r
1023\r
1024 PushBool (&StackPtr, Operator);\r
1025 break;\r
1026\r
1027 default:\r
1028 return FALSE;\r
1029 }\r
1030\r
1031 Operator = PopBool (&StackPtr);\r
1032 Operator2 = PopBool (&StackPtr);\r
1033 PushBool (&StackPtr, (BOOLEAN) (Operator && Operator2));\r
1034 break;\r
1035\r
1036 case EFI_IFR_OR_OP:\r
1037 Iterator++;\r
1038 if (Iterator->Operand == EFI_IFR_NOT_OP) {\r
1039 NotOperator = TRUE;\r
1040 Iterator++;\r
1041 }\r
1042\r
1043 if (Iterator->QuestionId1 != INVALID_OFFSET_VALUE) {\r
1044 ExtractNvValue (FileFormTags, Iterator->VariableNumber, Width, Iterator->QuestionId1, (VOID **) &MapBuffer);\r
1045 ExtractNvValue (FileFormTags, Iterator->VariableNumber2, Width, Iterator->QuestionId2, (VOID **) &MapBuffer2);\r
1046 if (MapBuffer != NULL) {\r
1047 if (Width == 2) {\r
1048 MapValue = *MapBuffer;\r
1049 } else {\r
1050 MapValue = (UINT8) *MapBuffer;\r
1051 }\r
1052\r
1053 FreePool (MapBuffer);\r
1054 }\r
1055\r
1056 if (MapBuffer2 != NULL) {\r
1057 if (Width == 2) {\r
1058 MapValue2 = *MapBuffer2;\r
1059 } else {\r
1060 MapValue2 = (UINT8) *MapBuffer2;\r
1061 }\r
1062\r
1063 FreePool (MapBuffer2);\r
1064 }\r
1065 }\r
1066\r
1067 switch (Iterator->Operand) {\r
1068 case EFI_IFR_EQ_ID_VAL_OP:\r
1069 //\r
1070 // If Not - flip the results\r
1071 //\r
1072 if (NotOperator) {\r
1073 Operator = (BOOLEAN)!(MapValue == Iterator->Value);\r
1074 } else {\r
1075 Operator = (BOOLEAN) (MapValue == Iterator->Value);\r
1076 }\r
1077\r
1078 PushBool (&StackPtr, Operator);\r
1079 break;\r
1080\r
1081 //\r
1082 // In the case of external variable values, we must read the variable which is\r
1083 // named by the human readable version of the OpCode->VariableId and the guid of the formset\r
1084 //\r
1085 case EFI_IFR_EQ_VAR_VAL_OP:\r
1086 UnicodeValueToString (\r
1087 VariableName,\r
1088 FALSE,\r
1089 (UINTN) Iterator->QuestionId1,\r
1090 (sizeof (VariableName) / sizeof (VariableName[0])) - 1\r
1091 );\r
1092\r
1093 SizeOfVariable = 0;\r
1094\r
1095 ExtractRequestedNvMap (FileFormTags, Iterator->VariableNumber, &VariableDefinition);\r
1096\r
1097 Status = BooleanVariableWorker (\r
1098 VariableName,\r
1099 VariableDefinition,\r
1100 StackPtr,\r
1101 &SizeOfVariable,\r
1102 &VariableData\r
1103 );\r
1104\r
1105 if (!EFI_ERROR (Status)) {\r
1106 if (SizeOfVariable == 1) {\r
1107 CopyMem (&MapValue, VariableData, 1);\r
1108 } else {\r
1109 CopyMem (&MapValue, VariableData, 2);\r
1110 }\r
1111 //\r
1112 // If Not - flip the results\r
1113 //\r
1114 if (NotOperator) {\r
1115 PushBool (&StackPtr, (BOOLEAN)!(MapValue == Iterator->Value));\r
1116 } else {\r
1117 PushBool (&StackPtr, (BOOLEAN) (MapValue == Iterator->Value));\r
1118 }\r
1119 }\r
1120 break;\r
1121\r
1122 case EFI_IFR_EQ_ID_ID_OP:\r
1123 //\r
1124 // If Not - flip the results\r
1125 //\r
1126 if (NotOperator) {\r
1127 Operator = (BOOLEAN)!(MapValue == MapValue2);\r
1128 } else {\r
1129 Operator = (BOOLEAN) (MapValue == MapValue2);\r
1130 }\r
1131\r
1132 PushBool (&StackPtr, Operator);\r
1133 break;\r
1134\r
1135 case EFI_IFR_EQ_ID_LIST_OP:\r
1136 for (Index = 0; Index < Iterator->ListLength; Index++) {\r
1137 //\r
1138 // If Not - flip the results\r
1139 //\r
1140 if (NotOperator) {\r
1141 Operator = (BOOLEAN)!(MapValue == Iterator->ValueList[Index]);\r
1142 } else {\r
1143 Operator = (BOOLEAN) (MapValue == Iterator->ValueList[Index]);\r
1144 }\r
1145 //\r
1146 // If We are trying to make sure that MapValue != Item[x], keep looking through\r
1147 // the list to make sure we don't equal any other items\r
1148 //\r
1149 if (Operator && NotOperator) {\r
1150 continue;\r
1151 }\r
1152 //\r
1153 // If MapValue == Item, then we have succeeded (first found is good enough)\r
1154 //\r
1155 if (Operator) {\r
1156 break;\r
1157 }\r
1158 }\r
1159\r
1160 PushBool (&StackPtr, Operator);\r
1161 break;\r
1162\r
1163 default:\r
1164 return FALSE;\r
1165 }\r
1166\r
1167 Operator = PopBool (&StackPtr);\r
1168 Operator2 = PopBool (&StackPtr);\r
1169 PushBool (&StackPtr, (BOOLEAN) (Operator || Operator2));\r
1170 break;\r
1171\r
1172 case EFI_IFR_NOT_OP:\r
1173 //\r
1174 // To check whether Ifr is legacy. Once every boolean expression.\r
1175 //\r
1176 if (IsLegacy == 0) {\r
1177 IsLegacy = PredicateIfrType (Iterator);\r
1178 }\r
1179 if (IsLegacy == 0x2) {\r
1180 PostOrderEvaluate (FileFormTags, Width, &Iterator, &StackPtr);\r
1181 break;\r
1182 }\r
1183\r
1184 //\r
1185 // I don't need to set the NotOperator (I know that I have to NOT this in this case\r
1186 //\r
1187 Iterator++;\r
1188\r
1189 if (Iterator->Operand == EFI_IFR_OR_OP) {\r
1190 OrOperator = TRUE;\r
1191 Iterator++;\r
1192 }\r
1193\r
1194 if (Iterator->Operand == EFI_IFR_AND_OP) {\r
1195 AndOperator = TRUE;\r
1196 Iterator++;\r
1197 }\r
1198\r
1199 if (Iterator->QuestionId1 != INVALID_OFFSET_VALUE) {\r
1200 ExtractNvValue (FileFormTags, Iterator->VariableNumber, Width, Iterator->QuestionId1, (VOID **) &MapBuffer);\r
1201 ExtractNvValue (FileFormTags, Iterator->VariableNumber2, Width, Iterator->QuestionId2, (VOID **) &MapBuffer2);\r
1202 if (MapBuffer != NULL) {\r
1203 if (Width == 2) {\r
1204 MapValue = *MapBuffer;\r
1205 } else {\r
1206 MapValue = (UINT8) *MapBuffer;\r
1207 }\r
1208\r
1209 FreePool (MapBuffer);\r
1210 }\r
1211\r
1212 if (MapBuffer2 != NULL) {\r
1213 if (Width == 2) {\r
1214 MapValue2 = *MapBuffer2;\r
1215 } else {\r
1216 MapValue2 = (UINT8) *MapBuffer2;\r
1217 }\r
1218\r
1219 FreePool (MapBuffer2);\r
1220 }\r
1221 }\r
1222\r
1223 switch (Iterator->Operand) {\r
1224 case EFI_IFR_EQ_ID_VAL_OP:\r
1225 Operator = (BOOLEAN)!(MapValue == Iterator->Value);\r
1226 PushBool (&StackPtr, Operator);\r
1227 break;\r
1228\r
1229 //\r
1230 // In the case of external variable values, we must read the variable which is\r
1231 // named by the human readable version of the OpCode->VariableId and the guid of the formset\r
1232 //\r
1233 case EFI_IFR_EQ_VAR_VAL_OP:\r
1234 UnicodeValueToString (\r
1235 VariableName,\r
1236 FALSE,\r
1237 (UINTN) Iterator->QuestionId1,\r
1238 (sizeof (VariableName) / sizeof (VariableName[0])) - 1\r
1239 );\r
1240\r
1241 SizeOfVariable = 0;\r
1242\r
1243 ExtractRequestedNvMap (FileFormTags, Iterator->VariableNumber, &VariableDefinition);\r
1244\r
1245 Status = BooleanVariableWorker (\r
1246 VariableName,\r
1247 VariableDefinition,\r
1248 StackPtr,\r
1249 &SizeOfVariable,\r
1250 &VariableData\r
1251 );\r
1252\r
1253 if (!EFI_ERROR (Status)) {\r
1254 if (SizeOfVariable == 1) {\r
1255 CopyMem (&MapValue, VariableData, 1);\r
1256 } else {\r
1257 CopyMem (&MapValue, VariableData, 2);\r
1258 }\r
1259\r
1260 PushBool (&StackPtr, (BOOLEAN)!(MapValue == Iterator->Value));\r
1261 }\r
1262 break;\r
1263\r
1264 case EFI_IFR_EQ_ID_ID_OP:\r
1265 Operator = (BOOLEAN)!(MapValue == MapValue2);\r
1266 PushBool (&StackPtr, Operator);\r
1267 break;\r
1268\r
1269 case EFI_IFR_EQ_ID_LIST_OP:\r
1270 for (Index = 0; Index < Iterator->ListLength; Index++) {\r
1271 Operator = (BOOLEAN)!(MapValue == Iterator->ValueList[Index]);\r
1272 if (Operator) {\r
1273 continue;\r
1274 }\r
1275 }\r
1276\r
1277 PushBool (&StackPtr, Operator);\r
1278 break;\r
1279\r
1280 default:\r
1281 return FALSE;\r
1282 }\r
1283\r
1284 Operator = PopBool (&StackPtr);\r
1285 Operator2 = PopBool (&StackPtr);\r
1286\r
1287 if (OrOperator) {\r
1288 PushBool (&StackPtr, (BOOLEAN) (Operator || Operator2));\r
1289 }\r
1290\r
1291 if (AndOperator) {\r
1292 PushBool (&StackPtr, (BOOLEAN) (Operator && Operator2));\r
1293 }\r
1294\r
1295 if (!OrOperator && !AndOperator) {\r
1296 PushBool (&StackPtr, Operator);\r
1297 }\r
1298 break;\r
1299\r
1300 case EFI_IFR_TRUE_OP:\r
1301 //\r
1302 // To check whether Ifr is legacy. Once every boolean expression.\r
1303 //\r
1304 if (IsLegacy == 0) {\r
1305 IsLegacy = PredicateIfrType (Iterator);\r
1306 }\r
1307 if (IsLegacy == 0x2) {\r
1308 PostOrderEvaluate (FileFormTags, Width, &Iterator, &StackPtr);\r
1309 break;\r
1310 }\r
1311 break;\r
1312\r
1313 case EFI_IFR_FALSE_OP:\r
1314 //\r
1315 // To check whether Ifr is legacy. Once every boolean expression.\r
1316 //\r
1317 if (IsLegacy == 0) {\r
1318 IsLegacy = PredicateIfrType (Iterator);\r
1319 }\r
1320 if (IsLegacy == 0x2) {\r
1321 PostOrderEvaluate (FileFormTags, Width, &Iterator, &StackPtr);\r
1322 break;\r
1323 }\r
1324 break;\r
1325\r
1326 case EFI_IFR_END_IF_OP:\r
1327 Operator = PopBool (&StackPtr);\r
1328 //\r
1329 // If there is an error, return, otherwise keep looking - there might\r
1330 // be another test that causes an error\r
1331 //\r
1332 if (Operator) {\r
1333 if (Complex && CosmeticConsistency) {\r
1334 return EFI_SUCCESS;\r
1335 } else {\r
1336 return Operator;\r
1337 }\r
1338 } else {\r
1339 //\r
1340 // If not doing a global consistency check, the endif is the REAL terminator of this operation\r
1341 // This is used for grayout/suppress operations. InconsistentIf is a global operation so the EndIf is\r
1342 // not the end-all be-all of terminators.\r
1343 //\r
1344 if (!Complex) {\r
1345 return Operator;\r
1346 }\r
1347 break;\r
1348 }\r
1349\r
1350 default:\r
1351 //\r
1352 // Must have hit a non-consistency related op-code after a suppress/grayout\r
1353 //\r
1354 if (ArtificialEnd) {\r
1355 ArtificialEnd = FALSE;\r
1356 Operator = PopBool (&StackPtr);\r
1357 return Operator;\r
1358 }\r
1359\r
1360 goto Done;\r
1361 }\r
1362\r
1363 Iterator++;\r
1364 }\r
1365\r
1366Done:\r
1367 return FALSE;\r
1368}\r