biosxml: run dos2unix

Signed-off-by: Patrick Williams <patrick@stwcx.xyz>
Change-Id: Ie3977e37d069f676a2f84b498c49cda5bb9e00da
diff --git a/include/biosxml.hpp b/include/biosxml.hpp
index 573115d..39af77c 100644
--- a/include/biosxml.hpp
+++ b/include/biosxml.hpp
@@ -1,878 +1,878 @@
-#pragma once

-

-#include "tinyxml2.h"

-

-#include <phosphor-logging/elog-errors.hpp>

-#include <phosphor-logging/log.hpp>

-

-#include <map>

-#include <sstream>

-#include <stack>

-#include <string>

-#include <variant>

-#include <vector>

-

-namespace bios

-{

-/* Can hold one 'option'

- * For example

- *  <option text="TIS" value="0x0"/>

- */

-using OptionType = std::tuple<std::string, std::variant<int64_t, std::string>>;

-

-/* Can hold one 'options'

- * For example

- *  <options>

- *		<option text="TIS" value="0x0"/>

- *		<option text="PTP FIFO" value="0x1"/>

- *		<option text="PTP CRB" value="0x2"/>

- *	</options>

- */

-using OptionTypeVector = std::vector<OptionType>;

-

-/* Can hold one 'knob'

- * For example

- *  <knob  type="scalar" setupType="oneof" name="TpmDeviceInterfaceAttempt"

- *  varstoreIndex="14" prompt="Attempt PTP TPM Device Interface"

- *  description="Attempt PTP TPM Device Interface: PTP FIFO, PTP CRB" size="1"

- *  offset="0x0005" depex="Sif( _LIST_ TpmDevice _EQU_ 0 1 ) _AND_ Sif(

- *  TpmDeviceInterfacePtpFifoSupported _EQU_ 0 OR

- *  TpmDeviceInterfacePtpCrbSupported _EQU_ 0 )" default="0x00"

- *CurrentVal="0x00"> <options> <option text="TIS" value="0x0"/> <option

- *text="PTP FIFO" value="0x1"/> <option text="PTP CRB" value="0x2"/>

- *		</options>

- *	</knob>

- */

-using BiosBaseTableTypeEntry =

-    std::tuple<std::string, bool, std::string, std::string, std::string,

-               std::variant<int64_t, std::string>,

-               std::variant<int64_t, std::string>, OptionTypeVector>;

-

-/* Can hold one 'biosknobs'

- * biosknobs has array of 'knob' */

-using BiosBaseTableType = std::map<std::string, BiosBaseTableTypeEntry>;

-

-namespace knob

-{

-/* These are the operators we support in a 'depex' expression

- * Note: We also support '_LIST_', 'Sif', 'Gif', 'Dif', and 'NOT'. But they are

- * handeled sepeartely. */

-enum class DepexOperators

-{

-    unknown = 0,

-    OR,

-    AND,

-    GT,

-    GTE,

-    LTE,

-    LT,

-    EQU,

-    NEQ,

-    MODULO

-};

-

-namespace option

-{

-/* Can hold one 'option' */

-struct option

-{

-    option(std::string text, std::string value) :

-        text(std::move(text)), value(std::move(value))

-    {}

-

-    std::string text;

-    std::string value;

-};

-} // namespace option

-

-/* Can hold one 'knob' */

-struct knob

-{

-    knob(std::string nameStr, std::string currentValStr, int currentVal,

-         std::string descriptionStr, std::string defaultStr,

-         std::string promptStr, std::string depexStr,

-         std::string& setupTypeStr) :

-        nameStr(std::move(nameStr)),

-        currentValStr(std::move(currentValStr)), currentVal(currentVal),

-        descriptionStr(std::move(descriptionStr)),

-        defaultStr(std::move(defaultStr)), promptStr(std::move(promptStr)),

-        depexStr(std::move(depexStr)), depex(false),

-        readOnly(("ReadOnly" == setupTypeStr) ? true : false)

-    {}

-

-    bool depex;

-    bool readOnly;

-    int currentVal;

-

-    std::string nameStr;

-    std::string currentValStr;

-    std::string descriptionStr;

-    std::string defaultStr;

-    std::string promptStr;

-    std::string depexStr;

-

-    /* Can hold one 'options' */

-    std::vector<option::option> options;

-};

-} // namespace knob

-

-/* Class capable of computing 'depex' expression. */

-class Depex

-{

-  public:

-    Depex(std::vector<knob::knob>& knobs) : mKnobs(knobs)

-    {}

-

-    /* Compute 'depex' expression of all knobs in 'biosknobs'. */

-    void compute()

-    {

-        mError.clear();

-

-        for (auto& knob : mKnobs)

-        {

-            /* if 'depex' == "TRUE" no need to execute expression. */

-            if ("TRUE" == knob.depexStr)

-            {

-                knob.depex = true;

-            }

-            else if (!knob.readOnly)

-            {

-                int value = 0;

-

-                if (!evaluateExpression(knob.depexStr, value))

-                {

-                    mError.emplace_back("bad depex: " + knob.depexStr +

-                                        " in knob: " + knob.nameStr);

-                }

-                else

-                {

-                    if (value)

-                    {

-                        knob.depex = true;

-                    }

-                }

-            }

-        }

-    }

-

-    /* Returns the number of 'knob's which have a bad 'depex' expression. */

-    size_t getErrorCount()

-    {

-        return mError.size();

-    }

-

-    /* Prints all the 'knob's which have a bad 'depex' expression. */

-    void printError()

-    {

-        for (auto& error : mError)

-        {

-            phosphor::logging::log<phosphor::logging::level::ERR>(

-                error.c_str());

-        }

-    }

-

-  private:

-    /* Returns 'true' if the argument string is a number. */

-    bool isNumber(const std::string& s)

-    {

-        return !s.empty() &&

-               std::find_if(s.begin(), s.end(), [](unsigned char c) {

-                   return !std::isdigit(c);

-               }) == s.end();

-    }

-

-    /* Returns 'true' if the argument string is hex representation of a number.

-     */

-    bool isHexNotation(std::string const& s)

-    {

-        return s.compare(0, 2, "0x") == 0 && s.size() > 2 &&

-               s.find_first_not_of("0123456789abcdefABCDEF", 2) ==

-                   std::string::npos;

-    }

-

-    /* Function to find current value of a 'knob'

-     * search is done using 'knob' attribute 'name' */

-    bool getValue(std::string& variableName, int& value)

-    {

-        for (auto& knob : mKnobs)

-        {

-            if (knob.nameStr == variableName)

-            {

-                value = knob.currentVal;

-                return true;

-            }

-        }

-

-        std::string error =

-            "Unable to find knob: " + variableName + " in knob list\n";

-        phosphor::logging::log<phosphor::logging::level::ERR>(error.c_str());

-

-        return false;

-    }

-

-    /* Get the expression enclosed within brackets, i.e., between '(' and ')' */

-    bool getSubExpression(const std::string& expression,

-                          std::string& subExpression, size_t& i)

-    {

-        int level = 1;

-        subExpression.clear();

-

-        for (; i < expression.length(); i++)

-        {

-            if (expression[i] == '(')

-            {

-                ++level;

-            }

-            else if (expression[i] == ')')

-            {

-                --level;

-                if (level == 0)

-                {

-                    break;

-                }

-            }

-

-            subExpression.push_back(expression[i]);

-        }

-

-        if (!subExpression.empty())

-        {

-            return true;

-        }

-

-        return false;

-    }

-

-    /* Function to handle operator '_LIST_'

-     * Convert a '_LIST_' expression to a normal expression

-     * Example "_LIST_ VariableA _EQU_ 0 1" is converted to "VariableA _EQU_ 0

-     * OR VariableA _EQU_ 1" */

-    bool getListExpression(const std::string& expression,

-                           std::string& subExpression, size_t& i)

-    {

-        subExpression.clear();

-

-        int cnt = 0;

-        std::string variableStr;

-        std::string operatorStr;

-

-        for (; i < expression.length(); i++)

-        {

-            if (expression[i] == '(')

-            {

-                return false;

-            }

-            else if (expression[i] == ')')

-            {

-                break;

-            }

-            else if (expression[i] == ' ')

-            {

-                /* whitespace */

-                continue;

-            }

-            else

-            {

-                std::string word;

-

-                /* Get the next word in expression string */

-                while ((i < expression.length()) && (expression[i] != ' '))

-                {

-                    word.push_back(expression[i++]);

-                }

-

-                if (word == "_OR_" || word == "OR" || word == "_AND_" ||

-                    word == "AND" || word == "NOT")

-                {

-                    i = i - word.length();

-                    break;

-                }

-

-                ++cnt;

-

-                if (cnt == 1)

-                {

-                    variableStr = word;

-                }

-                else if (cnt == 2)

-                {

-                    operatorStr = word;

-                }

-                else

-                {

-                    if (cnt > 3)

-                    {

-                        subExpression += " OR ";

-                    }

-

-                    subExpression += "( ";

-                    subExpression += variableStr;

-                    subExpression += " ";

-                    subExpression += operatorStr;

-                    subExpression += " ";

-                    subExpression += word;

-                    subExpression += " )";

-                }

-            }

-        }

-

-        if (!subExpression.empty())

-        {

-            return true;

-        }

-

-        return false;

-    }

-

-    /* Function to handle operator 'NOT'

-     * 1) Find the variable

-     * 2) apply NOT on the variable */

-    bool getNotValue(const std::string& expression, size_t& i, int& value)

-    {

-        std::string word;

-

-        for (; i < expression.length(); i++)

-        {

-            if (expression[i] == ' ')

-            {

-                /* whitespace */

-                continue;

-            }

-            else

-            {

-                /* Get the next word in expression string */

-                while ((i < expression.length()) && (expression[i] != ' '))

-                {

-                    word.push_back(expression[i++]);

-                }

-

-                break;

-            }

-        }

-

-        if (!word.empty())

-        {

-            if (getValue(word, value))

-            {

-                value = !value;

-                return true;

-            }

-        }

-

-        return false;

-    }

-

-    /* 1) Pop one operator from operator stack, example 'OR'

-     * 2) Pop two variable from variable stack, example VarA and VarB

-     * 3) Push back result of 'VarA OR VarB' to variable stack

-     * 4) Repeat till operator stack is empty

-     *

-     * The last variable in variable stack is the output of the expression. */

-    bool evaluateExprStack(std::stack<int>& values,

-                           std::stack<knob::DepexOperators>& operators,

-                           int& output)

-    {

-        if (values.size() != (operators.size() + 1))

-        {

-            return false;

-        }

-

-        while (!operators.empty())

-        {

-            int b = values.top();

-            values.pop();

-

-            int a = values.top();

-            values.pop();

-

-            switch (operators.top())

-            {

-                case knob::DepexOperators::OR:

-                    values.emplace(a | b);

-                    break;

-

-                case knob::DepexOperators::AND:

-                    values.emplace(a & b);

-                    break;

-

-                case knob::DepexOperators::EQU:

-                    if (a == b)

-                    {

-                        values.emplace(1);

-                        break;

-                    }

-

-                    values.emplace(0);

-                    break;

-

-                case knob::DepexOperators::NEQ:

-                    if (a != b)

-                    {

-                        values.emplace(1);

-                        break;

-                    }

-

-                    values.emplace(0);

-                    break;

-

-                case knob::DepexOperators::LTE:

-                    if (a <= b)

-                    {

-                        values.emplace(1);

-                        break;

-                    }

-

-                    values.emplace(0);

-                    break;

-

-                case knob::DepexOperators::LT:

-                    if (a < b)

-                    {

-                        values.emplace(1);

-                        break;

-                    }

-

-                    values.emplace(0);

-                    break;

-

-                case knob::DepexOperators::GTE:

-                    if (a >= b)

-                    {

-                        values.emplace(1);

-                        break;

-                    }

-

-                    values.emplace(0);

-                    break;

-

-                case knob::DepexOperators::GT:

-                    if (a > b)

-                    {

-                        values.emplace(1);

-                        break;

-                    }

-

-                    values.emplace(0);

-                    break;

-

-                case knob::DepexOperators::MODULO:

-                    if (b == 0)

-                    {

-                        return false;

-                    }

-                    values.emplace(a % b);

-                    break;

-

-                default:

-                    return false;

-            }

-

-            operators.pop();

-        }

-

-        if (values.size() == 1)

-        {

-            output = values.top();

-            values.pop();

-

-            return true;

-        }

-

-        return false;

-    }

-

-    /* Evaluvate one 'depex' expression

-     * 1) Find a word in expression string

-     * 2) If word is a variable push to variable stack

-     * 3) If word is a operator push to operator stack

-     *

-     * Execute the stack at end to get the result of expression. */

-    bool evaluateExpression(const std::string& expression, int& output)

-    {

-        if (expression.empty())

-        {

-            return false;

-        }

-

-        size_t i;

-        int value;

-        std::stack<int> values;

-        std::stack<knob::DepexOperators> operators;

-        std::string subExpression;

-

-        for (i = 0; i < expression.length(); i++)

-        {

-            if (expression[i] == ' ')

-            {

-                /* whitespace */

-                continue;

-            }

-            else

-            {

-                std::string word;

-

-                /* Get the next word in expression string */

-                while ((i < expression.length()) && (expression[i] != ' '))

-                {

-                    word.push_back(expression[i++]);

-                }

-

-                if (word == "_OR_" || word == "OR")

-                {

-                    /* OR and AND has more precedence than other operators

-                     * To handle statements like "a != b or c != d"

-                     * we need to execute, for above example, both '!=' before

-                     * 'or' */

-                    if (!operators.empty())

-                    {

-                        if (!evaluateExprStack(values, operators, value))

-                        {

-                            return false;

-                        }

-

-                        values.emplace(value);

-                    }

-

-                    operators.emplace(knob::DepexOperators::OR);

-                }

-                else if (word == "_AND_" || word == "AND")

-                {

-                    /* OR and AND has more precedence than other operators

-                     * To handle statements like "a == b and c == d"

-                     * we need to execute, for above example, both '==' before

-                     * 'and' */

-                    if (!operators.empty())

-                    {

-                        if (!evaluateExprStack(values, operators, value))

-                        {

-                            return false;

-                        }

-

-                        values.emplace(value);

-                    }

-

-                    operators.emplace(knob::DepexOperators::AND);

-                }

-                else if (word == "_LTE_")

-                {

-                    operators.emplace(knob::DepexOperators::LTE);

-                }

-                else if (word == "_LT_")

-                {

-                    operators.emplace(knob::DepexOperators::LT);

-                }

-                else if (word == "_GTE_")

-                {

-                    operators.emplace(knob::DepexOperators::GTE);

-                }

-                else if (word == "_GT_")

-                {

-                    operators.emplace(knob::DepexOperators::GT);

-                }

-                else if (word == "_NEQ_")

-                {

-                    operators.emplace(knob::DepexOperators::NEQ);

-                }

-                else if (word == "_EQU_")

-                {

-                    operators.emplace(knob::DepexOperators::EQU);

-                }

-                else if (word == "%")

-                {

-                    operators.emplace(knob::DepexOperators::MODULO);

-                }

-                else

-                {

-                    /* Handle 'Sif(', 'Gif(', 'Dif(' and '('

-                     * by taking the inner/sub expression and evaluating it */

-                    if (word.back() == '(')

-                    {

-                        if (!getSubExpression(expression, subExpression, i))

-                            break;

-

-                        if (!evaluateExpression(subExpression, value))

-                            break;

-                    }

-                    else if (word == "_LIST_")

-                    {

-                        if (!getListExpression(expression, subExpression, i))

-                            break;

-

-                        --i;

-

-                        if (!evaluateExpression(subExpression, value))

-                            break;

-                    }

-                    else if (word == "NOT")

-                    {

-                        if (!getNotValue(expression, i, value))

-                            break;

-                    }

-                    else if (isNumber(word) || isHexNotation(word))

-                    {

-                        try

-                        {

-                            value = std::stoi(word);

-                        }

-                        catch (std::exception& ex)

-                        {

-                            phosphor::logging::log<

-                                phosphor::logging::level::ERR>(ex.what());

-                            return false;

-                        }

-                    }

-                    else

-                    {

-                        if (!getValue(word, value))

-                            break;

-                    }

-

-                    values.emplace(value);

-                }

-            }

-        }

-

-        if (i == expression.length())

-        {

-            if (evaluateExprStack(values, operators, output))

-            {

-                return true;

-            }

-        }

-

-        return false;

-    }

-

-  private:

-    /* To store all 'knob's in 'biosknobs' */

-    std::vector<knob::knob>& mKnobs;

-

-    /* To store all bad 'depex' expression */

-    std::vector<std::string> mError;

-};

-

-class Xml

-{

-  public:

-    Xml(const char* filePath) : mDepex(std::make_unique<Depex>(mKnobs))

-    {

-        if (!getKnobs(filePath))

-        {

-            std::string error =

-                "Unable to get knobs in file: " + std::string(filePath);

-            throw std::runtime_error(error);

-        }

-    }

-

-    /* Fill Bios table with all 'knob's which have output of 'depex' expression

-     * as 'true' */

-    bool getBaseTable(bios::BiosBaseTableType& baseTable)

-    {

-        baseTable.clear();

-

-        for (auto& knob : mKnobs)

-        {

-            if (knob.depex)

-            {

-                std::string text =

-                    "xyz.openbmc_project.BIOSConfig.Manager.BoundType.OneOf";

-                bios::OptionTypeVector options;

-

-                for (auto& option : knob.options)

-                {

-                    options.emplace_back(text, option.value);

-                }

-

-                bios::BiosBaseTableTypeEntry baseTableEntry = std::make_tuple(

-                    "xyz.openbmc_project.BIOSConfig.Manager.AttributeType."

-                    "String",

-                    false, knob.nameStr, knob.descriptionStr, "./",

-                    knob.currentValStr, knob.defaultStr, options);

-

-                baseTable.emplace(knob.nameStr, baseTableEntry);

-            }

-        }

-

-        if (!baseTable.empty())

-        {

-            return true;

-        }

-

-        return false;

-    }

-

-    /* Execute all 'depex' expression */

-    bool doDepexCompute()

-    {

-        mDepex->compute();

-

-        if (mDepex->getErrorCount())

-        {

-            mDepex->printError();

-            return false;

-        }

-

-        return true;

-    }

-

-  private:

-    /* Get 'option' */

-    void getOption(tinyxml2::XMLElement* pOption)

-    {

-        if (pOption)

-        {

-            std::string valueStr;

-            std::string textStr;

-

-            if (pOption->Attribute("text"))

-                valueStr = pOption->Attribute("text");

-

-            if (pOption->Attribute("value"))

-                textStr = pOption->Attribute("value");

-

-            mKnobs.back().options.emplace_back(pOption->Attribute("text"),

-                                               pOption->Attribute("value"));

-        }

-    }

-

-    /* Get 'options' */

-    void getOptions(tinyxml2::XMLElement* pKnob)

-    {

-        uint16_t reserveCnt = 0;

-

-        /* Get node options inside knob */

-        tinyxml2::XMLElement* pOptions = pKnob->FirstChildElement("options");

-

-        if (pOptions)

-        {

-            for (tinyxml2::XMLElement* pOption =

-                     pOptions->FirstChildElement("option");

-                 pOption; pOption = pOption->NextSiblingElement("option"))

-            {

-                ++reserveCnt;

-            }

-

-            mKnobs.back().options.reserve(reserveCnt);

-

-            /* Loop through all option inside options */

-            for (tinyxml2::XMLElement* pOption =

-                     pOptions->FirstChildElement("option");

-                 pOption; pOption = pOption->NextSiblingElement("option"))

-            {

-                getOption(pOption);

-            }

-        }

-    }

-

-    /* Get 'knob' */

-    void getKnob(tinyxml2::XMLElement* pKnob)

-    {

-        if (pKnob)

-        {

-            int currentVal = 0;

-            std::string nameStr;

-            std::string currentValStr;

-            std::string descriptionStr;

-            std::string defaultStr;

-            std::string depexStr;

-            std::string promptStr;

-            std::string setupTypeStr;

-

-            if (!pKnob->Attribute("name") || !pKnob->Attribute("CurrentVal"))

-            {

-                return;

-            }

-

-            nameStr = pKnob->Attribute("name");

-            currentValStr = pKnob->Attribute("CurrentVal");

-

-            try

-            {

-                currentVal = std::stoi(currentValStr);

-            }

-            catch (std::exception& ex)

-            {

-                phosphor::logging::log<phosphor::logging::level::ERR>(

-                    ex.what());

-                return;

-            }

-

-            if (pKnob->Attribute("description"))

-                descriptionStr = pKnob->Attribute("description");

-

-            if (pKnob->Attribute("default"))

-                defaultStr = pKnob->Attribute("default");

-

-            if (pKnob->Attribute("depex"))

-                depexStr = pKnob->Attribute("depex");

-

-            if (pKnob->Attribute("prompt"))

-                promptStr = pKnob->Attribute("prompt");

-

-            if (pKnob->Attribute("setupType"))

-                setupTypeStr = pKnob->Attribute("setupType");

-

-            mKnobs.emplace_back(nameStr, currentValStr, currentVal,

-                                descriptionStr, defaultStr, promptStr, depexStr,

-                                setupTypeStr);

-

-            getOptions(pKnob);

-        }

-    }

-

-    /* Get 'biosknobs' */

-    bool getKnobs(const char* biosXmlFilePath)

-    {

-        uint16_t reserveCnt = 0;

-

-        mKnobs.clear();

-

-        tinyxml2::XMLDocument biosXml;

-

-        /* Load the XML file into the Doc instance */

-        biosXml.LoadFile(biosXmlFilePath);

-

-        /* Get 'SYSTEM' */

-        tinyxml2::XMLElement* pRootElement = biosXml.RootElement();

-        if (pRootElement)

-        {

-            /* Get 'biosknobs' inside 'SYSTEM' */

-            tinyxml2::XMLElement* pBiosknobs =

-                pRootElement->FirstChildElement("biosknobs");

-            if (pBiosknobs)

-            {

-                for (tinyxml2::XMLElement* pKnob =

-                         pBiosknobs->FirstChildElement("knob");

-                     pKnob; pKnob = pKnob->NextSiblingElement("knob"))

-                {

-                    ++reserveCnt;

-                }

-

-                /* reserve before emplace_back will avoids realloc(s) */

-                mKnobs.reserve(reserveCnt);

-

-                for (tinyxml2::XMLElement* pKnob =

-                         pBiosknobs->FirstChildElement("knob");

-                     pKnob; pKnob = pKnob->NextSiblingElement("knob"))

-                {

-                    getKnob(pKnob);

-                }

-            }

-        }

-

-        if (!mKnobs.empty())

-        {

-            return true;

-        }

-

-        return false;

-    }

-

-  private:

-    /* To store all 'knob's in 'biosknobs' */

-    std::vector<knob::knob> mKnobs;

-

-    /* Object of Depex class to compute 'depex' expression */

-    std::unique_ptr<Depex> mDepex;

-};

-} // namespace bios

+#pragma once
+
+#include "tinyxml2.h"
+
+#include <phosphor-logging/elog-errors.hpp>
+#include <phosphor-logging/log.hpp>
+
+#include <map>
+#include <sstream>
+#include <stack>
+#include <string>
+#include <variant>
+#include <vector>
+
+namespace bios
+{
+/* Can hold one 'option'
+ * For example
+ *  <option text="TIS" value="0x0"/>
+ */
+using OptionType = std::tuple<std::string, std::variant<int64_t, std::string>>;
+
+/* Can hold one 'options'
+ * For example
+ *  <options>
+ *		<option text="TIS" value="0x0"/>
+ *		<option text="PTP FIFO" value="0x1"/>
+ *		<option text="PTP CRB" value="0x2"/>
+ *	</options>
+ */
+using OptionTypeVector = std::vector<OptionType>;
+
+/* Can hold one 'knob'
+ * For example
+ *  <knob  type="scalar" setupType="oneof" name="TpmDeviceInterfaceAttempt"
+ *  varstoreIndex="14" prompt="Attempt PTP TPM Device Interface"
+ *  description="Attempt PTP TPM Device Interface: PTP FIFO, PTP CRB" size="1"
+ *  offset="0x0005" depex="Sif( _LIST_ TpmDevice _EQU_ 0 1 ) _AND_ Sif(
+ *  TpmDeviceInterfacePtpFifoSupported _EQU_ 0 OR
+ *  TpmDeviceInterfacePtpCrbSupported _EQU_ 0 )" default="0x00"
+ *CurrentVal="0x00"> <options> <option text="TIS" value="0x0"/> <option
+ *text="PTP FIFO" value="0x1"/> <option text="PTP CRB" value="0x2"/>
+ *		</options>
+ *	</knob>
+ */
+using BiosBaseTableTypeEntry =
+    std::tuple<std::string, bool, std::string, std::string, std::string,
+               std::variant<int64_t, std::string>,
+               std::variant<int64_t, std::string>, OptionTypeVector>;
+
+/* Can hold one 'biosknobs'
+ * biosknobs has array of 'knob' */
+using BiosBaseTableType = std::map<std::string, BiosBaseTableTypeEntry>;
+
+namespace knob
+{
+/* These are the operators we support in a 'depex' expression
+ * Note: We also support '_LIST_', 'Sif', 'Gif', 'Dif', and 'NOT'. But they are
+ * handeled sepeartely. */
+enum class DepexOperators
+{
+    unknown = 0,
+    OR,
+    AND,
+    GT,
+    GTE,
+    LTE,
+    LT,
+    EQU,
+    NEQ,
+    MODULO
+};
+
+namespace option
+{
+/* Can hold one 'option' */
+struct option
+{
+    option(std::string text, std::string value) :
+        text(std::move(text)), value(std::move(value))
+    {}
+
+    std::string text;
+    std::string value;
+};
+} // namespace option
+
+/* Can hold one 'knob' */
+struct knob
+{
+    knob(std::string nameStr, std::string currentValStr, int currentVal,
+         std::string descriptionStr, std::string defaultStr,
+         std::string promptStr, std::string depexStr,
+         std::string& setupTypeStr) :
+        nameStr(std::move(nameStr)),
+        currentValStr(std::move(currentValStr)), currentVal(currentVal),
+        descriptionStr(std::move(descriptionStr)),
+        defaultStr(std::move(defaultStr)), promptStr(std::move(promptStr)),
+        depexStr(std::move(depexStr)), depex(false),
+        readOnly(("ReadOnly" == setupTypeStr) ? true : false)
+    {}
+
+    bool depex;
+    bool readOnly;
+    int currentVal;
+
+    std::string nameStr;
+    std::string currentValStr;
+    std::string descriptionStr;
+    std::string defaultStr;
+    std::string promptStr;
+    std::string depexStr;
+
+    /* Can hold one 'options' */
+    std::vector<option::option> options;
+};
+} // namespace knob
+
+/* Class capable of computing 'depex' expression. */
+class Depex
+{
+  public:
+    Depex(std::vector<knob::knob>& knobs) : mKnobs(knobs)
+    {}
+
+    /* Compute 'depex' expression of all knobs in 'biosknobs'. */
+    void compute()
+    {
+        mError.clear();
+
+        for (auto& knob : mKnobs)
+        {
+            /* if 'depex' == "TRUE" no need to execute expression. */
+            if ("TRUE" == knob.depexStr)
+            {
+                knob.depex = true;
+            }
+            else if (!knob.readOnly)
+            {
+                int value = 0;
+
+                if (!evaluateExpression(knob.depexStr, value))
+                {
+                    mError.emplace_back("bad depex: " + knob.depexStr +
+                                        " in knob: " + knob.nameStr);
+                }
+                else
+                {
+                    if (value)
+                    {
+                        knob.depex = true;
+                    }
+                }
+            }
+        }
+    }
+
+    /* Returns the number of 'knob's which have a bad 'depex' expression. */
+    size_t getErrorCount()
+    {
+        return mError.size();
+    }
+
+    /* Prints all the 'knob's which have a bad 'depex' expression. */
+    void printError()
+    {
+        for (auto& error : mError)
+        {
+            phosphor::logging::log<phosphor::logging::level::ERR>(
+                error.c_str());
+        }
+    }
+
+  private:
+    /* Returns 'true' if the argument string is a number. */
+    bool isNumber(const std::string& s)
+    {
+        return !s.empty() &&
+               std::find_if(s.begin(), s.end(), [](unsigned char c) {
+                   return !std::isdigit(c);
+               }) == s.end();
+    }
+
+    /* Returns 'true' if the argument string is hex representation of a number.
+     */
+    bool isHexNotation(std::string const& s)
+    {
+        return s.compare(0, 2, "0x") == 0 && s.size() > 2 &&
+               s.find_first_not_of("0123456789abcdefABCDEF", 2) ==
+                   std::string::npos;
+    }
+
+    /* Function to find current value of a 'knob'
+     * search is done using 'knob' attribute 'name' */
+    bool getValue(std::string& variableName, int& value)
+    {
+        for (auto& knob : mKnobs)
+        {
+            if (knob.nameStr == variableName)
+            {
+                value = knob.currentVal;
+                return true;
+            }
+        }
+
+        std::string error =
+            "Unable to find knob: " + variableName + " in knob list\n";
+        phosphor::logging::log<phosphor::logging::level::ERR>(error.c_str());
+
+        return false;
+    }
+
+    /* Get the expression enclosed within brackets, i.e., between '(' and ')' */
+    bool getSubExpression(const std::string& expression,
+                          std::string& subExpression, size_t& i)
+    {
+        int level = 1;
+        subExpression.clear();
+
+        for (; i < expression.length(); i++)
+        {
+            if (expression[i] == '(')
+            {
+                ++level;
+            }
+            else if (expression[i] == ')')
+            {
+                --level;
+                if (level == 0)
+                {
+                    break;
+                }
+            }
+
+            subExpression.push_back(expression[i]);
+        }
+
+        if (!subExpression.empty())
+        {
+            return true;
+        }
+
+        return false;
+    }
+
+    /* Function to handle operator '_LIST_'
+     * Convert a '_LIST_' expression to a normal expression
+     * Example "_LIST_ VariableA _EQU_ 0 1" is converted to "VariableA _EQU_ 0
+     * OR VariableA _EQU_ 1" */
+    bool getListExpression(const std::string& expression,
+                           std::string& subExpression, size_t& i)
+    {
+        subExpression.clear();
+
+        int cnt = 0;
+        std::string variableStr;
+        std::string operatorStr;
+
+        for (; i < expression.length(); i++)
+        {
+            if (expression[i] == '(')
+            {
+                return false;
+            }
+            else if (expression[i] == ')')
+            {
+                break;
+            }
+            else if (expression[i] == ' ')
+            {
+                /* whitespace */
+                continue;
+            }
+            else
+            {
+                std::string word;
+
+                /* Get the next word in expression string */
+                while ((i < expression.length()) && (expression[i] != ' '))
+                {
+                    word.push_back(expression[i++]);
+                }
+
+                if (word == "_OR_" || word == "OR" || word == "_AND_" ||
+                    word == "AND" || word == "NOT")
+                {
+                    i = i - word.length();
+                    break;
+                }
+
+                ++cnt;
+
+                if (cnt == 1)
+                {
+                    variableStr = word;
+                }
+                else if (cnt == 2)
+                {
+                    operatorStr = word;
+                }
+                else
+                {
+                    if (cnt > 3)
+                    {
+                        subExpression += " OR ";
+                    }
+
+                    subExpression += "( ";
+                    subExpression += variableStr;
+                    subExpression += " ";
+                    subExpression += operatorStr;
+                    subExpression += " ";
+                    subExpression += word;
+                    subExpression += " )";
+                }
+            }
+        }
+
+        if (!subExpression.empty())
+        {
+            return true;
+        }
+
+        return false;
+    }
+
+    /* Function to handle operator 'NOT'
+     * 1) Find the variable
+     * 2) apply NOT on the variable */
+    bool getNotValue(const std::string& expression, size_t& i, int& value)
+    {
+        std::string word;
+
+        for (; i < expression.length(); i++)
+        {
+            if (expression[i] == ' ')
+            {
+                /* whitespace */
+                continue;
+            }
+            else
+            {
+                /* Get the next word in expression string */
+                while ((i < expression.length()) && (expression[i] != ' '))
+                {
+                    word.push_back(expression[i++]);
+                }
+
+                break;
+            }
+        }
+
+        if (!word.empty())
+        {
+            if (getValue(word, value))
+            {
+                value = !value;
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    /* 1) Pop one operator from operator stack, example 'OR'
+     * 2) Pop two variable from variable stack, example VarA and VarB
+     * 3) Push back result of 'VarA OR VarB' to variable stack
+     * 4) Repeat till operator stack is empty
+     *
+     * The last variable in variable stack is the output of the expression. */
+    bool evaluateExprStack(std::stack<int>& values,
+                           std::stack<knob::DepexOperators>& operators,
+                           int& output)
+    {
+        if (values.size() != (operators.size() + 1))
+        {
+            return false;
+        }
+
+        while (!operators.empty())
+        {
+            int b = values.top();
+            values.pop();
+
+            int a = values.top();
+            values.pop();
+
+            switch (operators.top())
+            {
+                case knob::DepexOperators::OR:
+                    values.emplace(a | b);
+                    break;
+
+                case knob::DepexOperators::AND:
+                    values.emplace(a & b);
+                    break;
+
+                case knob::DepexOperators::EQU:
+                    if (a == b)
+                    {
+                        values.emplace(1);
+                        break;
+                    }
+
+                    values.emplace(0);
+                    break;
+
+                case knob::DepexOperators::NEQ:
+                    if (a != b)
+                    {
+                        values.emplace(1);
+                        break;
+                    }
+
+                    values.emplace(0);
+                    break;
+
+                case knob::DepexOperators::LTE:
+                    if (a <= b)
+                    {
+                        values.emplace(1);
+                        break;
+                    }
+
+                    values.emplace(0);
+                    break;
+
+                case knob::DepexOperators::LT:
+                    if (a < b)
+                    {
+                        values.emplace(1);
+                        break;
+                    }
+
+                    values.emplace(0);
+                    break;
+
+                case knob::DepexOperators::GTE:
+                    if (a >= b)
+                    {
+                        values.emplace(1);
+                        break;
+                    }
+
+                    values.emplace(0);
+                    break;
+
+                case knob::DepexOperators::GT:
+                    if (a > b)
+                    {
+                        values.emplace(1);
+                        break;
+                    }
+
+                    values.emplace(0);
+                    break;
+
+                case knob::DepexOperators::MODULO:
+                    if (b == 0)
+                    {
+                        return false;
+                    }
+                    values.emplace(a % b);
+                    break;
+
+                default:
+                    return false;
+            }
+
+            operators.pop();
+        }
+
+        if (values.size() == 1)
+        {
+            output = values.top();
+            values.pop();
+
+            return true;
+        }
+
+        return false;
+    }
+
+    /* Evaluvate one 'depex' expression
+     * 1) Find a word in expression string
+     * 2) If word is a variable push to variable stack
+     * 3) If word is a operator push to operator stack
+     *
+     * Execute the stack at end to get the result of expression. */
+    bool evaluateExpression(const std::string& expression, int& output)
+    {
+        if (expression.empty())
+        {
+            return false;
+        }
+
+        size_t i;
+        int value;
+        std::stack<int> values;
+        std::stack<knob::DepexOperators> operators;
+        std::string subExpression;
+
+        for (i = 0; i < expression.length(); i++)
+        {
+            if (expression[i] == ' ')
+            {
+                /* whitespace */
+                continue;
+            }
+            else
+            {
+                std::string word;
+
+                /* Get the next word in expression string */
+                while ((i < expression.length()) && (expression[i] != ' '))
+                {
+                    word.push_back(expression[i++]);
+                }
+
+                if (word == "_OR_" || word == "OR")
+                {
+                    /* OR and AND has more precedence than other operators
+                     * To handle statements like "a != b or c != d"
+                     * we need to execute, for above example, both '!=' before
+                     * 'or' */
+                    if (!operators.empty())
+                    {
+                        if (!evaluateExprStack(values, operators, value))
+                        {
+                            return false;
+                        }
+
+                        values.emplace(value);
+                    }
+
+                    operators.emplace(knob::DepexOperators::OR);
+                }
+                else if (word == "_AND_" || word == "AND")
+                {
+                    /* OR and AND has more precedence than other operators
+                     * To handle statements like "a == b and c == d"
+                     * we need to execute, for above example, both '==' before
+                     * 'and' */
+                    if (!operators.empty())
+                    {
+                        if (!evaluateExprStack(values, operators, value))
+                        {
+                            return false;
+                        }
+
+                        values.emplace(value);
+                    }
+
+                    operators.emplace(knob::DepexOperators::AND);
+                }
+                else if (word == "_LTE_")
+                {
+                    operators.emplace(knob::DepexOperators::LTE);
+                }
+                else if (word == "_LT_")
+                {
+                    operators.emplace(knob::DepexOperators::LT);
+                }
+                else if (word == "_GTE_")
+                {
+                    operators.emplace(knob::DepexOperators::GTE);
+                }
+                else if (word == "_GT_")
+                {
+                    operators.emplace(knob::DepexOperators::GT);
+                }
+                else if (word == "_NEQ_")
+                {
+                    operators.emplace(knob::DepexOperators::NEQ);
+                }
+                else if (word == "_EQU_")
+                {
+                    operators.emplace(knob::DepexOperators::EQU);
+                }
+                else if (word == "%")
+                {
+                    operators.emplace(knob::DepexOperators::MODULO);
+                }
+                else
+                {
+                    /* Handle 'Sif(', 'Gif(', 'Dif(' and '('
+                     * by taking the inner/sub expression and evaluating it */
+                    if (word.back() == '(')
+                    {
+                        if (!getSubExpression(expression, subExpression, i))
+                            break;
+
+                        if (!evaluateExpression(subExpression, value))
+                            break;
+                    }
+                    else if (word == "_LIST_")
+                    {
+                        if (!getListExpression(expression, subExpression, i))
+                            break;
+
+                        --i;
+
+                        if (!evaluateExpression(subExpression, value))
+                            break;
+                    }
+                    else if (word == "NOT")
+                    {
+                        if (!getNotValue(expression, i, value))
+                            break;
+                    }
+                    else if (isNumber(word) || isHexNotation(word))
+                    {
+                        try
+                        {
+                            value = std::stoi(word);
+                        }
+                        catch (std::exception& ex)
+                        {
+                            phosphor::logging::log<
+                                phosphor::logging::level::ERR>(ex.what());
+                            return false;
+                        }
+                    }
+                    else
+                    {
+                        if (!getValue(word, value))
+                            break;
+                    }
+
+                    values.emplace(value);
+                }
+            }
+        }
+
+        if (i == expression.length())
+        {
+            if (evaluateExprStack(values, operators, output))
+            {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+  private:
+    /* To store all 'knob's in 'biosknobs' */
+    std::vector<knob::knob>& mKnobs;
+
+    /* To store all bad 'depex' expression */
+    std::vector<std::string> mError;
+};
+
+class Xml
+{
+  public:
+    Xml(const char* filePath) : mDepex(std::make_unique<Depex>(mKnobs))
+    {
+        if (!getKnobs(filePath))
+        {
+            std::string error =
+                "Unable to get knobs in file: " + std::string(filePath);
+            throw std::runtime_error(error);
+        }
+    }
+
+    /* Fill Bios table with all 'knob's which have output of 'depex' expression
+     * as 'true' */
+    bool getBaseTable(bios::BiosBaseTableType& baseTable)
+    {
+        baseTable.clear();
+
+        for (auto& knob : mKnobs)
+        {
+            if (knob.depex)
+            {
+                std::string text =
+                    "xyz.openbmc_project.BIOSConfig.Manager.BoundType.OneOf";
+                bios::OptionTypeVector options;
+
+                for (auto& option : knob.options)
+                {
+                    options.emplace_back(text, option.value);
+                }
+
+                bios::BiosBaseTableTypeEntry baseTableEntry = std::make_tuple(
+                    "xyz.openbmc_project.BIOSConfig.Manager.AttributeType."
+                    "String",
+                    false, knob.nameStr, knob.descriptionStr, "./",
+                    knob.currentValStr, knob.defaultStr, options);
+
+                baseTable.emplace(knob.nameStr, baseTableEntry);
+            }
+        }
+
+        if (!baseTable.empty())
+        {
+            return true;
+        }
+
+        return false;
+    }
+
+    /* Execute all 'depex' expression */
+    bool doDepexCompute()
+    {
+        mDepex->compute();
+
+        if (mDepex->getErrorCount())
+        {
+            mDepex->printError();
+            return false;
+        }
+
+        return true;
+    }
+
+  private:
+    /* Get 'option' */
+    void getOption(tinyxml2::XMLElement* pOption)
+    {
+        if (pOption)
+        {
+            std::string valueStr;
+            std::string textStr;
+
+            if (pOption->Attribute("text"))
+                valueStr = pOption->Attribute("text");
+
+            if (pOption->Attribute("value"))
+                textStr = pOption->Attribute("value");
+
+            mKnobs.back().options.emplace_back(pOption->Attribute("text"),
+                                               pOption->Attribute("value"));
+        }
+    }
+
+    /* Get 'options' */
+    void getOptions(tinyxml2::XMLElement* pKnob)
+    {
+        uint16_t reserveCnt = 0;
+
+        /* Get node options inside knob */
+        tinyxml2::XMLElement* pOptions = pKnob->FirstChildElement("options");
+
+        if (pOptions)
+        {
+            for (tinyxml2::XMLElement* pOption =
+                     pOptions->FirstChildElement("option");
+                 pOption; pOption = pOption->NextSiblingElement("option"))
+            {
+                ++reserveCnt;
+            }
+
+            mKnobs.back().options.reserve(reserveCnt);
+
+            /* Loop through all option inside options */
+            for (tinyxml2::XMLElement* pOption =
+                     pOptions->FirstChildElement("option");
+                 pOption; pOption = pOption->NextSiblingElement("option"))
+            {
+                getOption(pOption);
+            }
+        }
+    }
+
+    /* Get 'knob' */
+    void getKnob(tinyxml2::XMLElement* pKnob)
+    {
+        if (pKnob)
+        {
+            int currentVal = 0;
+            std::string nameStr;
+            std::string currentValStr;
+            std::string descriptionStr;
+            std::string defaultStr;
+            std::string depexStr;
+            std::string promptStr;
+            std::string setupTypeStr;
+
+            if (!pKnob->Attribute("name") || !pKnob->Attribute("CurrentVal"))
+            {
+                return;
+            }
+
+            nameStr = pKnob->Attribute("name");
+            currentValStr = pKnob->Attribute("CurrentVal");
+
+            try
+            {
+                currentVal = std::stoi(currentValStr);
+            }
+            catch (std::exception& ex)
+            {
+                phosphor::logging::log<phosphor::logging::level::ERR>(
+                    ex.what());
+                return;
+            }
+
+            if (pKnob->Attribute("description"))
+                descriptionStr = pKnob->Attribute("description");
+
+            if (pKnob->Attribute("default"))
+                defaultStr = pKnob->Attribute("default");
+
+            if (pKnob->Attribute("depex"))
+                depexStr = pKnob->Attribute("depex");
+
+            if (pKnob->Attribute("prompt"))
+                promptStr = pKnob->Attribute("prompt");
+
+            if (pKnob->Attribute("setupType"))
+                setupTypeStr = pKnob->Attribute("setupType");
+
+            mKnobs.emplace_back(nameStr, currentValStr, currentVal,
+                                descriptionStr, defaultStr, promptStr, depexStr,
+                                setupTypeStr);
+
+            getOptions(pKnob);
+        }
+    }
+
+    /* Get 'biosknobs' */
+    bool getKnobs(const char* biosXmlFilePath)
+    {
+        uint16_t reserveCnt = 0;
+
+        mKnobs.clear();
+
+        tinyxml2::XMLDocument biosXml;
+
+        /* Load the XML file into the Doc instance */
+        biosXml.LoadFile(biosXmlFilePath);
+
+        /* Get 'SYSTEM' */
+        tinyxml2::XMLElement* pRootElement = biosXml.RootElement();
+        if (pRootElement)
+        {
+            /* Get 'biosknobs' inside 'SYSTEM' */
+            tinyxml2::XMLElement* pBiosknobs =
+                pRootElement->FirstChildElement("biosknobs");
+            if (pBiosknobs)
+            {
+                for (tinyxml2::XMLElement* pKnob =
+                         pBiosknobs->FirstChildElement("knob");
+                     pKnob; pKnob = pKnob->NextSiblingElement("knob"))
+                {
+                    ++reserveCnt;
+                }
+
+                /* reserve before emplace_back will avoids realloc(s) */
+                mKnobs.reserve(reserveCnt);
+
+                for (tinyxml2::XMLElement* pKnob =
+                         pBiosknobs->FirstChildElement("knob");
+                     pKnob; pKnob = pKnob->NextSiblingElement("knob"))
+                {
+                    getKnob(pKnob);
+                }
+            }
+        }
+
+        if (!mKnobs.empty())
+        {
+            return true;
+        }
+
+        return false;
+    }
+
+  private:
+    /* To store all 'knob's in 'biosknobs' */
+    std::vector<knob::knob> mKnobs;
+
+    /* Object of Depex class to compute 'depex' expression */
+    std::unique_ptr<Depex> mDepex;
+};
+} // namespace bios