--- /dev/null
+/*++\r
+\r
+Copyright (c) 2004 - 2007, Intel Corporation \r
+All rights reserved. This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution. The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php \r
+ \r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
+\r
+Module Name:\r
+\r
+ VfrServices.cpp\r
+\r
+Abstract:\r
+\r
+ Support routines for the VFR compiler\r
+ \r
+--*/ \r
+\r
+#include <stdio.h> // for FILE routines\r
+#include <stdlib.h> // for malloc() and free()\r
+\r
+#include "Tiano.h"\r
+#include "EfiUtilityMsgs.h"\r
+#include "EfiVfr.h"\r
+#include "VfrServices.h"\r
+\r
+#include EFI_PROTOCOL_DEFINITION (Hii)\r
+\r
+static const char *mSourceFileHeader[] = {\r
+ "//",\r
+ "// DO NOT EDIT -- auto-generated file",\r
+ "//",\r
+ "// This file is generated by the VFR compiler.",\r
+ "//",\r
+ NULL\r
+};\r
+\r
+typedef struct {\r
+ INT8 *Name;\r
+ INT32 Size;\r
+} IFR_OPCODE_SIZES;\r
+\r
+//\r
+// Create a table that can be used to do internal checking on the IFR\r
+// bytes we emit.\r
+//\r
+static const IFR_OPCODE_SIZES mOpcodeSizes[] = {\r
+ { 0, 0 }, // invalid\r
+ { "EFI_IFR_FORM", sizeof (EFI_IFR_FORM) },\r
+ { "EFI_IFR_SUBTITLE", sizeof (EFI_IFR_SUBTITLE) }, \r
+ { "EFI_IFR_TEXT", -6 }, //sizeof (EFI_IFR_TEXT) }, \r
+ { "unused 0x04 opcode", 0 }, // EFI_IFR_GRAPHIC_OP\r
+ { "EFI_IFR_ONE_OF", sizeof (EFI_IFR_ONE_OF) }, \r
+ { "EFI_IFR_CHECK_BOX", sizeof (EFI_IFR_CHECK_BOX) }, \r
+ { "EFI_IFR_NUMERIC", sizeof (EFI_IFR_NUMERIC) }, \r
+ { "EFI_IFR_PASSWORD", sizeof (EFI_IFR_PASSWORD) }, \r
+ { "EFI_IFR_ONE_OF_OPTION", sizeof (EFI_IFR_ONE_OF_OPTION) }, \r
+ { "EFI_IFR_SUPPRESS", sizeof (EFI_IFR_SUPPRESS) }, \r
+ { "EFI_IFR_END_FORM", sizeof (EFI_IFR_END_FORM) }, \r
+ { "EFI_IFR_HIDDEN", sizeof (EFI_IFR_HIDDEN) }, \r
+ { "EFI_IFR_END_FORM_SET", sizeof (EFI_IFR_END_FORM_SET) }, \r
+ { "EFI_IFR_FORM_SET", sizeof (EFI_IFR_FORM_SET) }, \r
+ { "EFI_IFR_REF", sizeof (EFI_IFR_REF) }, \r
+ { "EFI_IFR_END_ONE_OF", sizeof (EFI_IFR_END_ONE_OF) }, \r
+ { "EFI_IFR_INCONSISTENT", sizeof (EFI_IFR_INCONSISTENT) }, \r
+ { "EFI_IFR_EQ_ID_VAL", sizeof (EFI_IFR_EQ_ID_VAL) }, \r
+ { "EFI_IFR_EQ_ID_ID", sizeof (EFI_IFR_EQ_ID_ID) }, \r
+ { "EFI_IFR_EQ_ID_LIST", -sizeof (EFI_IFR_EQ_ID_LIST) }, \r
+ { "EFI_IFR_AND", sizeof (EFI_IFR_AND) }, \r
+ { "EFI_IFR_OR", sizeof (EFI_IFR_OR) }, \r
+ { "EFI_IFR_NOT", sizeof (EFI_IFR_NOT) }, \r
+ { "EFI_IFR_END_IF", sizeof (EFI_IFR_END_IF) }, \r
+ { "EFI_IFR_GRAYOUT", sizeof (EFI_IFR_GRAYOUT) }, \r
+ { "EFI_IFR_DATE", sizeof (EFI_IFR_DATE) / 3 }, \r
+ { "EFI_IFR_TIME", sizeof (EFI_IFR_TIME) / 3 }, \r
+ { "EFI_IFR_STRING", sizeof (EFI_IFR_STRING) }, \r
+ { "EFI_IFR_LABEL", sizeof (EFI_IFR_LABEL) }, \r
+ { "EFI_IFR_SAVE_DEFAULTS", sizeof (EFI_IFR_SAVE_DEFAULTS) }, \r
+ { "EFI_IFR_RESTORE_DEFAULTS", sizeof (EFI_IFR_RESTORE_DEFAULTS) }, \r
+ { "EFI_IFR_BANNER", sizeof (EFI_IFR_BANNER) },\r
+ { "EFI_IFR_INVENTORY", sizeof (EFI_IFR_INVENTORY) },\r
+ { "EFI_IFR_EQ_VAR_VAL_OP", sizeof (EFI_IFR_EQ_VAR_VAL) },\r
+ { "EFI_IFR_ORDERED_LIST_OP", sizeof (EFI_IFR_ORDERED_LIST) },\r
+ { "EFI_IFR_VARSTORE_OP", -sizeof (EFI_IFR_VARSTORE) },\r
+ { "EFI_IFR_VARSTORE_SELECT_OP", sizeof (EFI_IFR_VARSTORE_SELECT) },\r
+ { "EFI_IFR_VARSTORE_SELECT_PAIR_OP", sizeof (EFI_IFR_VARSTORE_SELECT_PAIR) },\r
+ { "EFI_IFR_TRUE", sizeof (EFI_IFR_TRUE)},\r
+ { "EFI_IFR_FALSE", sizeof (EFI_IFR_FALSE)},\r
+ { "EFI_IFR_GT", sizeof (EFI_IFR_GT)},\r
+ { "EFI_IFR_GE", sizeof (EFI_IFR_GE)},\r
+ { "EFI_IFR_OEM_DEFINED_OP", -2 },\r
+};\r
+\r
+\r
+VfrOpcodeHandler::VfrOpcodeHandler (\r
+ ) \r
+/*++\r
+\r
+Routine Description:\r
+ Constructor for the VFR opcode handling class.\r
+ \r
+Arguments:\r
+ None\r
+\r
+Returns:\r
+ None\r
+\r
+--*/\r
+{ \r
+ mIfrBytes = NULL; \r
+ mLastIfrByte = NULL;\r
+ mBytesWritten = 0;\r
+ mQueuedByteCount = 0;\r
+ mQueuedOpcodeByteValid = 0;\r
+ mPrimaryVarStoreId = 0;\r
+ mSecondaryVarStoreId = 0;\r
+ mSecondaryVarStoreIdSet = 0;\r
+ mPrimaryVarStoreIdSet = 0;\r
+ mDefaultVarStoreId = 0;\r
+}\r
+\r
+VOID \r
+VfrOpcodeHandler::SetVarStoreId (\r
+ UINT16 VarStoreId\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+ This function is invoked by the parser when a variable is referenced in the \r
+ VFR. Save the variable store (and set a flag) so that we can later determine \r
+ if we need to emit a varstore-select or varstore-select-pair opcode.\r
+ \r
+Arguments:\r
+ VarStoreId - ID of the variable store referenced in the VFR\r
+\r
+Returns:\r
+ None\r
+\r
+--*/\r
+{\r
+ mPrimaryVarStoreId = VarStoreId;\r
+ mPrimaryVarStoreIdSet = 1;\r
+}\r
+\r
+VOID \r
+VfrOpcodeHandler::SetSecondaryVarStoreId (\r
+ UINT16 VarStoreId\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+ This function is invoked by the parser when a secondary variable is \r
+ referenced in the VFR. Save the variable store (and set a flag) so \r
+ that we can later determine if we need to emit a varstore-select or \r
+ varstore-pair opcode.\r
+ \r
+Arguments:\r
+ VarStoreId - ID of the variable store referenced in the VFR\r
+\r
+Returns:\r
+ None\r
+\r
+--*/\r
+{\r
+ mSecondaryVarStoreId = VarStoreId;\r
+ mSecondaryVarStoreIdSet = 1;\r
+}\r
+\r
+VOID \r
+VfrOpcodeHandler::WriteIfrBytes (\r
+ ) \r
+/*++\r
+\r
+Routine Description:\r
+ This function is invoked at the end of parsing. Its purpose\r
+ is to write out all the IFR bytes that were queued up while\r
+ parsing.\r
+ \r
+Arguments:\r
+ None\r
+\r
+Returns:\r
+ None\r
+\r
+--*/\r
+{ \r
+ IFR_BYTE *Curr;\r
+ IFR_BYTE *Next;\r
+ UINT32 Count;\r
+ UINT32 LineCount;\r
+ UINT32 PoundLines;\r
+ UINT32 ByteCount;\r
+ INT8 Line[MAX_LINE_LEN];\r
+ INT8 *Cptr;\r
+ FILE *InFptr;\r
+ FILE *OutFptr;\r
+ UINT32 ListFile;\r
+ EFI_HII_IFR_PACK_HEADER IfrHeader;\r
+ UINT8 *Ptr;\r
+ FILE *IfrBinFptr;\r
+ UINT32 BytesLeftThisOpcode;\r
+ //\r
+ // If someone added a new opcode and didn't update our opcode sizes structure, error out.\r
+ //\r
+ if (sizeof(mOpcodeSizes) / sizeof (mOpcodeSizes[0]) != EFI_IFR_LAST_OPCODE + 1) {\r
+ Error (__FILE__, __LINE__, 0, "application error", "internal IFR binary table size is incorrect");\r
+ return;\r
+ }\r
+ //\r
+ // Flush the queue\r
+ //\r
+ FlushQueue (); \r
+ //\r
+ // If there have been any errors to this point, then skip dumping the IFR\r
+ // binary data. This way doing an nmake again will try to build it again, and\r
+ // the build will fail if they did not fix the problem.\r
+ //\r
+ if (GetUtilityStatus () != STATUS_ERROR) {\r
+ if ((IfrBinFptr = fopen (gOptions.IfrOutputFileName, "w")) == NULL) {\r
+ Error (PROGRAM_NAME, 0, 0, gOptions.IfrOutputFileName, "could not open file for writing");\r
+ return;\r
+ }\r
+ //\r
+ // Write the standard file header to the output file\r
+ //\r
+ WriteStandardFileHeader (IfrBinFptr);\r
+ //\r
+ // Write the structure header\r
+ //\r
+ fprintf (IfrBinFptr, "\nunsigned char %sBin[] = {", gOptions.VfrBaseFileName);\r
+ //\r
+ // Write the header\r
+ //\r
+ memset ((char *)&IfrHeader, 0, sizeof (IfrHeader));\r
+ IfrHeader.Header.Type = EFI_HII_IFR;\r
+ IfrHeader.Header.Length = mBytesWritten + sizeof (IfrHeader); \r
+ Ptr = (UINT8 *)&IfrHeader;\r
+ for (Count = 0; Count < sizeof (IfrHeader); Count++, Ptr++) {\r
+ if ((Count & 0x03) == 0) {\r
+ fprintf (IfrBinFptr, "\n ");\r
+ }\r
+ fprintf (IfrBinFptr, "0x%02X, ", *Ptr); \r
+ }\r
+ //\r
+ //\r
+ // Write all the IFR bytes\r
+ //\r
+ fprintf (IfrBinFptr, "\n // start of IFR data");\r
+ Curr = mIfrBytes;\r
+ Count = 0;\r
+ while (Curr != NULL) {\r
+ if ((Count & 0x0F) == 0) {\r
+ fprintf (IfrBinFptr, "\n ");\r
+ }\r
+ if (Curr->KeyByte != 0) {\r
+ fprintf (IfrBinFptr, "/*%c*/ ", Curr->KeyByte);\r
+ }\r
+ fprintf (IfrBinFptr, "0x%02X, ", Curr->OpcodeByte);\r
+ Count++;\r
+ Curr = Curr->Next;\r
+ }\r
+ fprintf (IfrBinFptr, "\n};\n\n");\r
+ //\r
+ //\r
+ // Close the file\r
+ //\r
+ fclose (IfrBinFptr); \r
+ IfrBinFptr = NULL;\r
+ }\r
+ //\r
+ // Write the bytes as binary data if the user specified to do so\r
+ //\r
+ if ((GetUtilityStatus () != STATUS_ERROR) && (gOptions.CreateIfrBinFile != 0)) {\r
+ //\r
+ // Use the Ifr output file name with a ".hpk" extension.\r
+ //\r
+ for (Cptr = gOptions.IfrOutputFileName + strlen (gOptions.IfrOutputFileName) - 1;\r
+ (*Cptr != '.') && (Cptr > gOptions.IfrOutputFileName) && (*Cptr != '\\');\r
+ Cptr--) {\r
+ //\r
+ // do nothing\r
+ //\r
+ }\r
+ if (*Cptr == '.') {\r
+ strcpy (Cptr, ".hpk");\r
+ } else {\r
+ strcat (gOptions.IfrOutputFileName, ".hpk");\r
+ }\r
+ if ((IfrBinFptr = fopen (gOptions.IfrOutputFileName, "wb")) == NULL) {\r
+ Error (PROGRAM_NAME, 0, 0, gOptions.IfrOutputFileName, "could not open file for writing");\r
+ return;\r
+ }\r
+ //\r
+ // Write the structure header\r
+ //\r
+ memset ((char *)&IfrHeader, 0, sizeof (IfrHeader));\r
+ IfrHeader.Header.Type = EFI_HII_IFR;\r
+ IfrHeader.Header.Length = mBytesWritten + sizeof (IfrHeader); \r
+ Ptr = (UINT8 *)&IfrHeader;\r
+ for (Count = 0; Count < sizeof (IfrHeader); Count++, Ptr++) {\r
+ fwrite (Ptr, 1, 1, IfrBinFptr);\r
+ }\r
+ //\r
+ //\r
+ // Write all the IFR bytes\r
+ //\r
+ Curr = mIfrBytes;\r
+ Count = 0;\r
+ while (Curr != NULL) {\r
+ fwrite (&Curr->OpcodeByte, 1, 1, IfrBinFptr);\r
+ Curr = Curr->Next;\r
+ }\r
+ //\r
+ //\r
+ // Close the file\r
+ //\r
+ fclose (IfrBinFptr); \r
+ IfrBinFptr = NULL;\r
+ }\r
+ //\r
+ // If creating a listing file, then open the input and output files\r
+ //\r
+ ListFile = 0;\r
+ if (gOptions.CreateListFile) {\r
+ //\r
+ // Open the input VFR file and the output list file\r
+ //\r
+ if ((InFptr = fopen (gOptions.PreprocessorOutputFileName, "r")) == NULL) {\r
+ Warning (PROGRAM_NAME, 0, 0, gOptions.PreprocessorOutputFileName, "could not open file for creating a list file");\r
+ } else {\r
+ if ((OutFptr = fopen (gOptions.VfrListFileName, "w")) == NULL) {\r
+ Warning (PROGRAM_NAME, 0, 0, gOptions.VfrListFileName, "could not open output list file for writing");\r
+ fclose (InFptr);\r
+ InFptr = NULL;\r
+ } else {\r
+ LineCount = 0;\r
+ ListFile = 1;\r
+ PoundLines = 0;\r
+ ByteCount = 0;\r
+ }\r
+ }\r
+ }\r
+ //\r
+ // Write the list file\r
+ //\r
+ if (ListFile) {\r
+ //\r
+ // Write out the VFR compiler version\r
+ //\r
+ fprintf (OutFptr, "//\n// VFR compiler version " VFR_COMPILER_VERSION "\n//\n");\r
+ Curr = mIfrBytes;\r
+ while (Curr != NULL) {\r
+ //\r
+ // Print lines until we reach the line of the current opcode\r
+ //\r
+ while (LineCount < PoundLines + Curr->LineNum) {\r
+ if (fgets (Line, sizeof (Line), InFptr) != NULL) {\r
+ //\r
+ // We should check for line length exceeded on the fgets(). Otherwise it\r
+ // throws the listing file output off. Future enhancement perhaps.\r
+ //\r
+ fprintf (OutFptr, "%s", Line);\r
+ if (strncmp (Line, "#line", 5) == 0) {\r
+ PoundLines++;\r
+ }\r
+ }\r
+ LineCount++;\r
+ }\r
+ //\r
+ // Print all opcodes with line numbers less than where we are now\r
+ //\r
+ BytesLeftThisOpcode = 0;\r
+ while ((Curr != NULL) && ((Curr->LineNum == 0) || (LineCount >= PoundLines + Curr->LineNum))) {\r
+ if (BytesLeftThisOpcode == 0) {\r
+ fprintf (OutFptr, ">%08X: ", ByteCount);\r
+ if (Curr->Next != NULL) {\r
+ BytesLeftThisOpcode = (UINT32)Curr->Next->OpcodeByte;\r
+ }\r
+ }\r
+ fprintf (OutFptr, "%02X ", (UINT32)Curr->OpcodeByte);\r
+ ByteCount++;\r
+ BytesLeftThisOpcode--;\r
+ if (BytesLeftThisOpcode == 0) {\r
+ fprintf (OutFptr, "\n");\r
+ }\r
+ Curr = Curr->Next;\r
+ }\r
+ }\r
+ //\r
+ // Dump any remaining lines from the input file\r
+ //\r
+ while (fgets (Line, sizeof (Line), InFptr) != NULL) {\r
+ fprintf (OutFptr, "%s", Line);\r
+ }\r
+ fclose (InFptr);\r
+ fclose (OutFptr);\r
+ }\r
+ //\r
+ // Debug code to make sure that each opcode we write out has as many\r
+ // bytes as the IFR structure requires. If there were errors, then\r
+ // don't do this step.\r
+ //\r
+ if (GetUtilityStatus () != STATUS_ERROR) {\r
+ Curr = mIfrBytes;\r
+ ByteCount = 0;\r
+ while (Curr != NULL) {\r
+ //\r
+ // First byte is the opcode, second byte is the length\r
+ //\r
+ if (Curr->Next == NULL) {\r
+ Error (__FILE__, __LINE__, 0, "application error", "last opcode written does not contain a length byte");\r
+ break;\r
+ }\r
+ Count = (UINT32)Curr->Next->OpcodeByte;\r
+ if (Count == 0) {\r
+ Error (\r
+ __FILE__, \r
+ __LINE__, \r
+ 0, \r
+ "application error", \r
+ "opcode with 0 length specified in output at offset 0x%X", \r
+ ByteCount\r
+ );\r
+ break;\r
+ }\r
+ //\r
+ // Check the length\r
+ //\r
+ if ((Curr->OpcodeByte > EFI_IFR_LAST_OPCODE) || (Curr->OpcodeByte == 0)) {\r
+ Error (\r
+ __FILE__, \r
+ __LINE__, \r
+ 0, \r
+ "application error", \r
+ "invalid opcode 0x%X in output at offset 0x%X", \r
+ (UINT32) Curr->OpcodeByte, ByteCount\r
+ );\r
+ } else if (mOpcodeSizes[Curr->OpcodeByte].Size < 0) {\r
+ //\r
+ // For those cases where the length is variable, the size is negative, and indicates\r
+ // the miniumum size.\r
+ //\r
+ if ((mOpcodeSizes[Curr->OpcodeByte].Size * -1) > Count) {\r
+ Error (\r
+ __FILE__, \r
+ __LINE__, \r
+ 0, \r
+ "application error", \r
+ "insufficient number of bytes written for %s at offset 0x%X",\r
+ mOpcodeSizes[Curr->OpcodeByte].Name, \r
+ ByteCount\r
+ );\r
+ }\r
+ } else {\r
+ //\r
+ // Check for gaps\r
+ //\r
+ if (mOpcodeSizes[Curr->OpcodeByte].Size == 0) {\r
+ Error (\r
+ __FILE__, \r
+ __LINE__, \r
+ 0, \r
+ "application error", \r
+ "invalid opcode 0x%X in output at offset 0x%X", \r
+ (UINT32)Curr->OpcodeByte, \r
+ ByteCount\r
+ );\r
+ } else {\r
+ //\r
+ // Check size\r
+ //\r
+ if (mOpcodeSizes[Curr->OpcodeByte].Size != Count) {\r
+ Error (\r
+ __FILE__, \r
+ __LINE__, \r
+ 0, \r
+ "application error", \r
+ "invalid number of bytes (%d written s/b %d) written for %s at offset 0x%X",\r
+ Count, \r
+ mOpcodeSizes[Curr->OpcodeByte].Size, \r
+ mOpcodeSizes[Curr->OpcodeByte].Name, \r
+ ByteCount\r
+ );\r
+ }\r
+ }\r
+ }\r
+ //\r
+ // Skip to next opcode\r
+ //\r
+ while (Count > 0) {\r
+ ByteCount++;\r
+ if (Curr == NULL) {\r
+ Error (__FILE__, __LINE__, 0, "application error", "last opcode written has invalid length");\r
+ break;\r
+ }\r
+ Curr = Curr->Next;\r
+ Count--;\r
+ }\r
+ }\r
+ }\r
+}\r
+\r
+VfrOpcodeHandler::~VfrOpcodeHandler(\r
+ ) \r
+/*++\r
+\r
+Routine Description:\r
+ Destructor for the VFR opcode handler. Free up memory allocated\r
+ while parsing the VFR script.\r
+ \r
+Arguments:\r
+ None\r
+\r
+Returns:\r
+ None\r
+\r
+--*/\r
+{\r
+ IFR_BYTE *Curr;\r
+ IFR_BYTE *Next;\r
+ //\r
+ // Free up the IFR bytes\r
+ //\r
+ Curr = mIfrBytes;\r
+ while (Curr != NULL) {\r
+ Next = Curr->Next;\r
+ free (Curr);\r
+ Curr = Next;\r
+ }\r
+}\r
+\r
+int \r
+VfrOpcodeHandler::AddOpcodeByte (\r
+ UINT8 OpcodeByte, \r
+ UINT32 LineNum\r
+ ) \r
+/*++\r
+\r
+Routine Description:\r
+ This function is invoked by the parser when a new IFR\r
+ opcode should be emitted.\r
+ \r
+Arguments:\r
+ OpcodeByte - the IFR opcode\r
+ LineNum - the line number from the source file that resulted\r
+ in the opcode being emitted.\r
+\r
+Returns:\r
+ 0 always\r
+\r
+--*/\r
+{\r
+ UINT32 Count;\r
+\r
+ FlushQueue();\r
+ //\r
+ // Now add this new byte\r
+ //\r
+ mQueuedOpcodeByte = OpcodeByte;\r
+ mQueuedLineNum = LineNum;\r
+ mQueuedOpcodeByteValid = 1;\r
+ return 0;\r
+}\r
+\r
+VOID \r
+VfrOpcodeHandler::AddByte (\r
+ UINT8 ByteVal, \r
+ UINT8 KeyByte\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+ This function is invoked by the parser when it determines\r
+ that more raw IFR bytes should be emitted to the output stream.\r
+ Here we just queue them up into an output buffer.\r
+ \r
+Arguments:\r
+ ByteVal - the raw byte to emit to the output IFR stream\r
+ KeyByte - a value that can be used for debug. \r
+\r
+Returns:\r
+ None\r
+\r
+--*/\r
+{\r
+ //\r
+ // Check for buffer overflow\r
+ //\r
+ if (mQueuedByteCount >= MAX_QUEUE_COUNT) {\r
+ Error (PROGRAM_NAME, 0, 0, NULL, "opcode queue overflow");\r
+ } else {\r
+ mQueuedBytes[mQueuedByteCount] = ByteVal;\r
+ mQueuedKeyBytes[mQueuedByteCount] = KeyByte;\r
+ mQueuedByteCount++;\r
+ }\r
+}\r
+\r
+int \r
+VfrOpcodeHandler::FlushQueue (\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+ This function is invoked to flush the internal IFR buffer.\r
+ \r
+Arguments:\r
+ None\r
+\r
+Returns:\r
+ 0 always\r
+\r
+--*/\r
+{\r
+ UINT32 Count;\r
+ UINT32 EmitNoneOnePair;\r
+\r
+ EmitNoneOnePair = 0;\r
+ //\r
+ // If the secondary varstore was specified, then we have to emit\r
+ // a varstore-select-pair opcode, which only applies to the following\r
+ // statement. \r
+ //\r
+ if (mSecondaryVarStoreIdSet) {\r
+ mSecondaryVarStoreIdSet = 0;\r
+ //\r
+ // If primary and secondary are the same as the current default\r
+ // varstore, then we don't have to do anything.\r
+ // Note that the varstore-select-pair only applies to the following\r
+ // opcode.\r
+ //\r
+ if ((mPrimaryVarStoreId != mSecondaryVarStoreId) || (mPrimaryVarStoreId != mDefaultVarStoreId)) {\r
+ IAddByte (EFI_IFR_VARSTORE_SELECT_PAIR_OP, 'O', mQueuedLineNum);\r
+ IAddByte ((UINT8)sizeof (EFI_IFR_VARSTORE_SELECT_PAIR), 'L', 0);\r
+ IAddByte ((UINT8)mPrimaryVarStoreId, 0, 0);\r
+ IAddByte ((UINT8)(mPrimaryVarStoreId >> 8), 0, 0);\r
+ IAddByte ((UINT8)mSecondaryVarStoreId, 0, 0);\r
+ IAddByte ((UINT8)(mSecondaryVarStoreId >> 8), 0, 0);\r
+ }\r
+ } else if (mPrimaryVarStoreIdSet != 0) {\r
+ mPrimaryVarStoreIdSet = 0;\r
+ if (mDefaultVarStoreId != mPrimaryVarStoreId) {\r
+ //\r
+ // The VFR statement referenced a different variable store \r
+ // than the last one we reported. Insert a new varstore select \r
+ // statement. \r
+ //\r
+ IAddByte (EFI_IFR_VARSTORE_SELECT_OP, 'O', mQueuedLineNum);\r
+ IAddByte ((UINT8)sizeof (EFI_IFR_VARSTORE_SELECT), 'L', 0);\r
+ IAddByte ((UINT8)mPrimaryVarStoreId, 0, 0);\r
+ IAddByte ((UINT8)(mPrimaryVarStoreId >> 8), 0, 0);\r
+ mDefaultVarStoreId = mPrimaryVarStoreId;\r
+ }\r
+ }\r
+ //\r
+ // Likely a new opcode is being added. Since each opcode item in the IFR has \r
+ // a header that specifies the size of the opcode item (which we don't\r
+ // know until we find the next opcode in the VFR), we queue up bytes\r
+ // until we know the size. Then we write them out. So flush the queue\r
+ // now.\r
+ //\r
+ if (mQueuedOpcodeByteValid != 0) {\r
+ // \r
+ // Add the previous opcode byte, the length byte, and the binary\r
+ // data.\r
+ //\r
+ IAddByte (mQueuedOpcodeByte, 'O', mQueuedLineNum);\r
+ IAddByte ((UINT8)(mQueuedByteCount + 2), 'L', 0);\r
+ for (Count = 0; Count < mQueuedByteCount; Count++) {\r
+ IAddByte (mQueuedBytes[Count], mQueuedKeyBytes[Count], 0); \r
+ }\r
+ mQueuedByteCount = 0;\r
+ mQueuedOpcodeByteValid = 0;\r
+ } \r
+ return 0;\r
+}\r
+\r
+int \r
+VfrOpcodeHandler::IAddByte (\r
+ UINT8 ByteVal, \r
+ UINT8 KeyByte, \r
+ UINT32 LineNum\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+ This internal function is used to add actual IFR bytes to\r
+ the output stream. Most other functions queue up the bytes\r
+ in an internal buffer. Once they come here, there's no\r
+ going back.\r
+\r
+ \r
+Arguments:\r
+ ByteVal - value to write to output \r
+ KeyByte - key value tied to the byte -- useful for debug\r
+ LineNum - line number from source file the byte resulted from\r
+\r
+Returns:\r
+ 0 - if successful\r
+ 1 - failed due to memory allocation failure\r
+\r
+--*/\r
+{\r
+ IFR_BYTE *NewByte;\r
+ NewByte = (IFR_BYTE *)malloc (sizeof (IFR_BYTE));\r
+ if (NewByte == NULL) {\r
+ return 1;\r
+ }\r
+ memset ((char *)NewByte, 0, sizeof (IFR_BYTE));\r
+ NewByte->OpcodeByte = ByteVal;\r
+ NewByte->KeyByte = KeyByte;\r
+ NewByte->LineNum = LineNum;\r
+ //\r
+ // Add to the list\r
+ //\r
+ if (mIfrBytes == NULL) {\r
+ mIfrBytes = NewByte;\r
+ } else {\r
+ mLastIfrByte->Next = NewByte;\r
+ } \r
+ mLastIfrByte = NewByte;\r
+ mBytesWritten++;\r
+ return 0;\r
+}\r
+\r
+VOID \r
+WriteStandardFileHeader (\r
+ FILE *OutFptr\r
+ ) \r
+/*++\r
+\r
+Routine Description:\r
+ This function is invoked to emit a standard header to an\r
+ output text file.\r
+ \r
+Arguments:\r
+ OutFptr - file to write the header to\r
+\r
+Returns:\r
+ None\r
+\r
+--*/\r
+{\r
+ UINT32 TempIndex;\r
+ for (TempIndex = 0; mSourceFileHeader[TempIndex] != NULL; TempIndex++) {\r
+ fprintf (OutFptr, "%s\n", mSourceFileHeader[TempIndex]);\r
+ }\r
+ //\r
+ // Write out the VFR compiler version\r
+ //\r
+ fprintf (OutFptr, "// VFR compiler version " VFR_COMPILER_VERSION "\n//\n");\r
+}\r