123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714 |
- // configuration.hpp
- //
- // Copyright (C) 2004-2020 MicroNeil Research Corporation.
- //
- // This software is released under the MIT license. See LICENSE.TXT.
-
- // What about this =============================================================
-
- // The configuration module provides a platform for reading configuration files
- // (or string data) containing well-formed xml and mapping that data to program
- // variables.
- //
- // The idea is to provide the ability for an object or application to provide
- // a modular "configuration" object that models a hierarchical collection of
- // "settings" that can be represented easily in code and in xml.
- //
- // The following is an example model of a configuration in code and that same
- // configuration fully populated in xml.
- //
- // The code might look like this...
- //
- // int IntValue, DefaultInt = 3;
- // double DblValue, DefaultDbl = 3.14159;
- // bool BooleanValue, DefaultBool = false;
- // string StringValue, DefaultString = "NoStringHere";
- //
- // SpecialConfigurator : public ConfigurationHandler { // Create a special handler to build a list
- // ...
- // public:
- //
- // ConfigurationHandler& Startup(ConfigurationElement& E) { // This function returns a handy handler to
- // return MyStartupConfigurationHandler; // (re) initialize this handler ;-)
- // }
- //
- // void Operator()() { // Each time the configurator is called
- // ...
- // }
- //
- // int Attribute1; // these items are interpreted and added
- // double Attribute2; // to the list. A ConfigurationHandler COULD
- // string Attribute3; // do something entirely different though ;-)
- // string Contents;
- // ...
- // } Special;
- //
- // ConfigurationElement SampleConfig("SampleConfiguration"); // Define a sample config (doc element)
- // SampleConfig // Populate the SampleConfig
- // .atStartCall(Special.Startup())
- // .Element("Integer", IntValue, DefaultInt).End() // Link an element to an int w/ default.
- // .Element("Double", DblValue, DefaultDbl).End("Double") // Link an element to a dbl w/ default.
- // .Element("String", StringValue, DefaultString).End("String") // Link an element to a string w/ default.
- // .Element("ComplexElements") // Create a sub element.
- // .Element("Complex1") // Sub element Complex1 has attributes.
- // .Attribute("IntAtt", IntValue, DefaultInt) // Complex1 has an integer attribute.
- // .Attribute("DblAtt", DblValue, DefaultDbl) // Complex1 has a dbl attribute.
- // .Element("IntAtt", IntValue).End() // IntAtt can also be set by a sub element.
- // .Element("DblAtt", DblValue).End() // DblAtt can also be set by a sub element.
- // .End() // That's it for Complex1.
- // .Element("Complex2") // Create the Complex2 sub element.
- // .Attribute("C2I", IntValue, DefaultInt) // C2I attribute.
- // .Attribute("C2D", DblValue) // C2D attribute - no default.
- // .Attribute("C2S", StringValue, DefultString) // C2S attribute - string w/ default.
- // .End("Complex2") // End of element throws if doesn't match.
- // .Element("Complex3", Special.Contents) // Element 3 using a special configurator.
- // .Attribute("A1", Special.Attribute1) // Set A1 and A2 and A3 and when the
- // .Attribute("A2", Special.Attribute2) // element has been completed, Special()
- // .Attribute("A3", Special.Attribute3) // will be called to record the entries.
- // .atEndCall(Special) // Here's where we register the handler.
- // .End() // Closing Complex3 to be ice.
- // .End() // Closing ComplexElements to be nice.
- // .End(); // Closing SampleConfiguration to be nice.
- //
- // The XML might look like this...
- //
- // <SampleConfiguration>
- // <Integer>10</Integer>
- // <Double>2.4</Double>
- // <String>This is a sample string</String>
- // <ComplexElements>
- // <Complex1 IntAtt="4" DblAtt="2.1324">
- // <IntAtt>24</IntAtt> <!-- changed IntAtt -->
- // </Complex1>
- // <Complex2 C2I='3' C2D='5.14' C2S='Some "string" we like' />
- // <Complex3> stuff in here </Complex3>
- // <Complex3> Another instance </Complex3>
- // <Complex3> Each one gets passed to Special() on activation </Complex3>
- // <Complex3> This way, Special() can build a list or some other </Complex3>
- // <Complex3> interesting thing with all of these. </Complex3>
- // <ComplexElements>
- // </SampleConfiguration>
- //
-
- // Include This Header Once Only ===============================================
-
- #pragma once
-
- #include <string>
- #include <vector>
- #include <sstream>
- #include <fstream>
- #include <cstring>
- #include <cstdlib>
- #include <list>
-
- namespace codedweller {
-
- class ConfigurationElement; // Elements exist
- class ConfigurationAttribute; // Attributes exist
- class ConfigurationData; // Data exists
- class ConfigurationTranslator; // Translators exist
- class ConfigurationMnemonic; // Mnemonics exist
- class Configurator; // Configurators exist
-
- //// Configuration Element /////////////////////////////////////////////////////
- //
- // Elements make up the core of a configuration. That is, a configuration is a
- // tree of elements. Elements translate directly to well formed xml elements in
- // a configuration file or string.
-
- class ConfigurationElement {
-
- private:
-
- std::string myName; // Elements have a name.
-
- // External important things I remember but don't touch...
-
- ConfigurationElement* myParent; // They may have a parrent.
-
- std::list<Configurator*> myStartConfigurators; // Call these when we start Interpret()
- std::list<Configurator*> myEndConfigurators; // Call these when we finish Interpret()
-
- // Internal / subordinate things I own and kill...
-
- std::list<ConfigurationAttribute*> myAttributes; // They may have a list of attributes.
- std::list<ConfigurationElement*> myElements; // They may have a list of sub-elements.
- std::list<ConfigurationMnemonic*> myMnemonics; // They may have a list of mnemonics.
- std::list<ConfigurationTranslator*> myTranslators; // They may have a list of translators.
-
- // During Interpret() operations we keep track of where we are seen...
-
- int myLine; // Last line number I was seen on.
- int myIndex; // Last char position I was seen on.
- int myLength; // Last segment length.
-
- bool myCleanFlag; // Keep track of initialization.
-
- bool myInitOnInterpretFlag; // Initialize() at each Interpret()?
-
- void runStartConfigurators(ConfigurationData& D); // Does what it says ;-)
- void runEndConfigurators(ConfigurationData& D); // Does what it says ;-)
-
- public:
-
- ConfigurationElement(const char* Name); // Must be constructed with a name
- ConfigurationElement(const std::string Name); // either c string or c++ string.
-
- ConfigurationElement(const char* Name, ConfigurationElement& Parent); // Sub-elements are constructed with a
- ConfigurationElement(const std::string Name, ConfigurationElement& Parent); // parrent.
-
- // Upon desctruction an element will delete all subordinate objects:
- // * All sub element objects.
- // * All attribute objects.
- // * All mnemonic objects.
- // * All translator objects.
- // It is important to use new when passing one of these objects to an
- // element or attribute to prevent problems with the delete operation.
- // NORMALLY these things would be created using factory methods on the
- // element and attribute objects themselves - so be careful.
- // It will not delete Configurators - they must
- // be deleted elsewhere because they may have been
- // re-used and this element wouldn't know about it ;-)
-
- ~ConfigurationElement(); // The descrutor clears and deletes all!
-
- // Elements can be probed for some simple, useful things.
-
- std::string Name(); // Get the name of this element.
- ConfigurationElement& Parent(); // Get the parent of this element.
- ConfigurationElement& Parent(ConfigurationElement& newParent); // Set the parent of this element.
-
- // Note - if there is no parent (an element is the root) then it will
- // return a reference to itself when Parent() is called.
-
- int Line(); // Get the last line number.
- int Index(); // Get the last data position.
- int Length(); // Get the last length.
-
- // Elements can contain either data or sub-elements.
-
- ConfigurationElement& Element(const char* Name); // Add a new sub element by c string name.
- ConfigurationElement& Element(const std::string Name); // Add a new sub element by c++ string name.
-
- //// Mapping element factory methods for convenience.
- //// Root-Node elements are _usually_ empty and without attributes in xml
- //// so we don't make any of that type of convenience constructor here.
-
- // char* versions
-
- ConfigurationElement& Element( // Mapping factory for convenience,
- const char* Name, // requires a name, of course,
- ConfigurationTranslator& newTranslator); // Add a Translator to this element.
-
- ConfigurationElement& Element( // Mapping factory for convenience,
- const char* Name, // requires a name, of course,
- std::string& x, std::string init = std::string("")); // Map to a string.
-
- ConfigurationElement& Element( // Mapping factory for convenience,
- const char* Name, // requires a name, of course,
- int& x, int init = 0, int radix = 0); // Map to an int.
-
- ConfigurationElement& Element( // Mapping factory for convenience,
- const char* Name, // requires a name, of course,
- double& x, double init = 0.0); // Map to a double.
-
- ConfigurationElement& Element( // Mapping factory for convenience,
- const char* Name, // requires a name, of course,
- bool& x, bool init = false); // Map to a boolean.
-
- // string versions
-
- ConfigurationElement& Element( // Mapping factory for convenience,
- const std::string Name, // requires a name, of course,
- ConfigurationTranslator& newTranslator); // Add a Translator to this element.
-
- ConfigurationElement& Element( // Mapping factory for convenience,
- const std::string Name, // requires a name, of course,
- std::string& x, std::string init = std::string("")); // Map to a string.
-
- ConfigurationElement& Element( // Mapping factory for convenience,
- const std::string Name, // requires a name, of course,
- int& x, int init = 0, int radix = 0); // Map to an int.
-
- ConfigurationElement& Element( // Mapping factory for convenience,
- const std::string Name, // requires a name, of course,
- double& x, double init = 0.0); // Map to a double.
-
- ConfigurationElement& Element( // Mapping factory for convenience,
- const std::string Name, // requires a name, of course,
- bool& x, bool init = false); // Map to a boolean.
-
- // End methods for heading back up the tree at the end of an element.
-
- class EndNameDoesNotMatch {}; // Throw when End(name) doesn't match.
-
- ConfigurationElement& End(); // Return this element's parent.
- ConfigurationElement& End(const char* Name); // Check the name and return the parent
- ConfigurationElement& End(const std::string Name); // if the name is correct - or throw!
-
- // Elements can have attributes.
-
- ConfigurationAttribute& Attribute(const char* Name); // Add an attribute using a cstring.
- ConfigurationAttribute& Attribute(const std::string Name); // Add an attribute using a c++ string.
-
- //// Mapping Attribute factory methods for convenience.
-
- // char* versions
-
- ConfigurationAttribute& Attribute( // Mapping factory for convenience,
- const char* Name, // requires a name, of course,
- ConfigurationTranslator& newTranslator); // Add a Translator to this element.
-
- ConfigurationAttribute& Attribute( // Mapping factory for convenience,
- const char* Name, // requires a name, of course,
- std::string& x, std::string init = std::string("")); // Map to a string.
-
- ConfigurationAttribute& Attribute( // Mapping factory for convenience,
- const char* Name, // requires a name, of course,
- int& x, int init = 0, int radix = 0); // Map to an int.
-
- ConfigurationAttribute& Attribute( // Mapping factory for convenience,
- const char* Name, // requires a name, of course,
- double& x, double init = 0.0); // Map to a double.
-
- ConfigurationAttribute& Attribute( // Mapping factory for convenience,
- const char* Name, // requires a name, of course,
- bool& x, bool init = false); // Map to a boolean.
-
- // string versions
-
- ConfigurationAttribute& Attribute( // Mapping factory for convenience,
- const std::string Name, // requires a name, of course,
- ConfigurationTranslator& newTranslator); // Add a Translator to this element.
-
- ConfigurationAttribute& Attribute( // Mapping factory for convenience,
- const std::string Name, // requires a name, of course,
- std::string& x, std::string init = std::string("")); // Map to a string.
-
- ConfigurationAttribute& Attribute( // Mapping factory for convenience,
- const std::string Name, // requires a name, of course,
- int& x, int init = 0, int radix = 0); // Map to an int.
-
- ConfigurationAttribute& Attribute( // Mapping factory for convenience,
- const std::string Name, // requires a name, of course,
- double& x, double init = 0.0); // Map to a double.
-
- ConfigurationAttribute& Attribute( // Mapping factory for convenience,
- const std::string Name, // requires a name, of course,
- bool& x, bool init = false); // Map to a boolean.
-
- // Elements can Initialize() at each Interpret() call.
-
- ConfigurationElement& setInitOnInterpret(); // Set the init on interpret flag.
-
- // Elements can call external functions to aid in special operations
- // such as building lists.
-
- ConfigurationElement& atStartCall(Configurator& Functor); // Add an atStart call-back to this element.
- ConfigurationElement& atEndCall(Configurator& Functor); // Add an atEnd call-back to this element.
-
- // Extracting data from the element's contents is done with
- // translators. A good set of primatives are built in, but the user
- // can also make their own. If an Element is mapped to more than
- // one then they are all called once the element's contents are
- // collected. A translator takes the data provided by the element,
- // converts it into the expected type, and sets one or more variables
- // to the converted value. Usually - just one variable.
-
- ConfigurationElement& mapTo(ConfigurationTranslator& newTranslator); // Add a Translator to this element.
- ConfigurationElement& mapTo(std::string& x, std::string init = std::string("")); // Map to a string.
- ConfigurationElement& mapTo(int& x, int init = 0, int radix = 0); // Map to an int.
- ConfigurationElement& mapTo(double& x, double init = 0.0); // Map to a double.
- ConfigurationElement& mapTo(bool& x, bool init = false); // Map to a boolean.
-
- // An Element's contents may use some special mnemonics to make a
- // configuration easier to understand and less error prone. When the
- // contents match a mnemnoic then the translation of the mnemonic is
- // passed to the Translators instead of the raw contents.
-
- ConfigurationElement& Mnemonic(const char* name, const char* value); // Add a mnemonic using c strings.
- ConfigurationElement& Mnemonic(const char* name, const std::string value); // Add a mnemonic using c & c++ strings.
- ConfigurationElement& Mnemonic(const std::string name, const char* value); // Add a mnemonic using c++ & c strings.
- ConfigurationElement& Mnemonic(const std::string name, const std::string value); // Add a mnemonic using c++ strings.
-
- // The way data gets into an element tree is that it is Interpret()ed
- // recursively. The data is loaded into a ConfigurationData object which
- // is passed to the top Element. That element interpretes the data, moves
- // the interpretation pointers, and passes the data on to it's subordinate
- // elements in turn. They do the same recursively. When the last sub -
- // element has had it's way with the data, the interpretation process is
- // complete. The ConfigurationData object will contain the original data
- // and a log of anything that happened during the interpretation process.
- //
- // Each time an element is asked to Interpret() data, it calls any atStart
- // configurators, translates any attributes, then either translates it's
- // contents or passes the data to it's children, then calls any atEnd
- // configurators.
- //
- // To ensure that the correct default values are used the Initialize() is
- // always called on all internal attributes and elements before any data is
- // interpreted. To prevent this from being inefficient, a boolean flag is
- // kept in each element to keep track of whether it is clean and if it is
- // then the call to Initialize will simply return (skipping subordinate
- // elements along the way).
- //
- // Interpret returns true if this object found itself at the current
- // Data.Index and false if not. This helps keep the recursive parsing
- // code simpler ;-)
-
- void initialize(); // Reset all translators to defaults.
-
- void notifyDirty(); // Set dirty (if translators change).
-
- bool interpret(ConfigurationData& Data); // (re) Interpret this data.
-
- };
-
- //// Configuration Attribute ///////////////////////////////////////////////////
- //
- // Attributes translate directly to well formed xml attributes (within the
- // start tag of an element).
-
- class ConfigurationAttribute {
-
- private:
-
- std::string myName; // Elements have a name.
- ConfigurationElement& myParent; // They may have a parrent.
-
- std::list<ConfigurationMnemonic*> myMnemonics; // They may have a list of mnemonics.
- std::list<ConfigurationTranslator*> myTranslators; // They may have a list of translators.
-
- int myLine; // Last line number I was seen on.
- int myIndex; // Last char position I was seen on.
- int myLength; // Last segment length.
-
- public:
-
- ConfigurationAttribute(const char* Name, ConfigurationElement& Parent); // Sub-elements are constructed with a
- ConfigurationAttribute(const std::string Name, ConfigurationElement& Parent); // parrent.
-
- // Attributes delete their Mnemonics and Translators when they go.
- // See Elements for similar warnings about objects provided to
- // this object... you must use new to be safe, or better yet - stick to
- // the built in factory methods ;-)
-
- ~ConfigurationAttribute(); // Crush, Kill, Destroy!
-
- // Attributes can be probed for some simple, useful things.
-
- std::string Name(); // Get the name of this attribute.
- ConfigurationElement& Parent(); // Get the parent of this attribute.
- int Line(); // Get the last line number.
- int Index(); // Get the last data position.
- int Length(); // Get the last length.
-
- void notifyDirty(); // Attributes use this when they change.
-
- // For convenience in building configurations, an Attribute offers
- // some call-through methods to it's parrent Element. This allows for
- // clear, concise .method() coding that mimics an outline of the
- // configuration structure.
-
- //// For switching back to the parent element and adding new sub-elements.
-
- ConfigurationElement& Element(const char* Name); // Add a new sub element by c string name.
- ConfigurationElement& Element(const std::string Name); // Add a new sub element by c++ string name.
-
- //// Mapping element factory methods for convenience.
- //// Root-Node elements are _usually_ empty and without attributes in xml
- //// so we don't make any of that type of convenience constructor here.
-
- // char* versions
-
- ConfigurationElement& Element( // Mapping factory for convenience,
- const char* Name, // requires a name, of course,
- ConfigurationTranslator& newTranslator); // Add a Translator to this element.
-
- ConfigurationElement& Element( // Mapping factory for convenience,
- const char* Name, // requires a name, of course,
- std::string& x, std::string init = std::string("")); // Map to a string.
-
- ConfigurationElement& Element( // Mapping factory for convenience,
- const char* Name, // requires a name, of course,
- int& x, int init = 0, int radix = 0); // Map to an int.
-
- ConfigurationElement& Element( // Mapping factory for convenience,
- const char* Name, // requires a name, of course,
- double& x, double init = 0.0); // Map to a double.
-
- ConfigurationElement& Element( // Mapping factory for convenience,
- const char* Name, // requires a name, of course,
- bool& x, bool init = false); // Map to a boolean.
-
- // string versions
-
- ConfigurationElement& Element( // Mapping factory for convenience,
- const std::string Name, // requires a name, of course,
- ConfigurationTranslator& newTranslator); // Add a Translator to this element.
-
- ConfigurationElement& Element( // Mapping factory for convenience,
- const std::string Name, // requires a name, of course,
- std::string& x, std::string init = std::string("")); // Map to a string.
-
- ConfigurationElement& Element( // Mapping factory for convenience,
- const std::string Name, // requires a name, of course,
- int& x, int init = 0, int radix = 0); // Map to an int.
-
- ConfigurationElement& Element( // Mapping factory for convenience,
- const std::string Name, // requires a name, of course,
- double& x, double init = 0.0); // Map to a double.
-
- ConfigurationElement& Element( // Mapping factory for convenience,
- const std::string Name, // requires a name, of course,
- bool& x, bool init = false); // Map to a boolean.
-
- // End methods for heading back up the tree at the end of an element.
-
- ConfigurationElement& End(); // Return this element's parent.
- ConfigurationElement& End(const char* Name); // Check the name and return the parent
- ConfigurationElement& End(const std::string Name); // if the name is correct - or throw!
-
- //// For adding new attributes to the parent element.
-
- ConfigurationAttribute& Attribute(const char* Name); // Add an attribute using a cstring.
- ConfigurationAttribute& Attribute(const std::string Name); // Add an attribute using a c++ string.
-
- //// Mapping Attribute factory methods for convenience.
-
- // char* versions
-
- ConfigurationAttribute& Attribute( // Mapping factory for convenience,
- const char* Name, // requires a name, of course,
- ConfigurationTranslator& newTranslator); // Add a Translator to this element.
-
- ConfigurationAttribute& Attribute( // Mapping factory for convenience,
- const char* Name, // requires a name, of course,
- std::string& x, std::string init = std::string("")); // Map to a string.
-
- ConfigurationAttribute& Attribute( // Mapping factory for convenience,
- const char* Name, // requires a name, of course,
- int& x, int init = 0, int radix = 0); // Map to an int.
-
- ConfigurationAttribute& Attribute( // Mapping factory for convenience,
- const char* Name, // requires a name, of course,
- double& x, double init = 0.0); // Map to a double.
-
- ConfigurationAttribute& Attribute( // Mapping factory for convenience,
- const char* Name, // requires a name, of course,
- bool& x, bool init = false); // Map to a boolean.
-
- // string versions
-
- ConfigurationAttribute& Attribute( // Mapping factory for convenience,
- const std::string Name, // requires a name, of course,
- ConfigurationTranslator& newTranslator); // Add a Translator to this element.
-
- ConfigurationAttribute& Attribute( // Mapping factory for convenience,
- const std::string Name, // requires a name, of course,
- std::string& x, std::string init = std::string("")); // Map to a string.
-
- ConfigurationAttribute& Attribute( // Mapping factory for convenience,
- const std::string Name, // requires a name, of course,
- int& x, int init = 0, int radix = 0); // Map to an int.
-
- ConfigurationAttribute& Attribute( // Mapping factory for convenience,
- const std::string Name, // requires a name, of course,
- double& x, double init = 0.0); // Map to a double.
-
- ConfigurationAttribute& Attribute( // Mapping factory for convenience,
- const std::string Name, // requires a name, of course,
- bool& x, bool init = false); // Map to a boolean.
-
- //// Set Init On Interprete for the parent element.
-
- ConfigurationElement& setInitOnInterpret(); // Set the init on interpret flag.
-
- //// For adding configurators to the parent element.
-
- ConfigurationElement& atStartCall(Configurator& Functor); // Add an atStart call-back to this element.
- ConfigurationElement& atEndCall(Configurator& Functor); // Add an atEnd call-back to this element.
-
- // Of course, the most useful thing about attributes is that they can
- // be mapped to variables using translators. The same as those that
- // apply to the parent element's contents. Here they are for use on this
- // attribute.
-
- ConfigurationAttribute& mapTo(ConfigurationTranslator& newTranslator); // Add a Translator to this attribute.
- ConfigurationAttribute& mapTo(std::string& x, std::string init = std::string("")); // Map to a string.
- ConfigurationAttribute& mapTo(int& x, int init, int radix = 0); // Map to an int.
- ConfigurationAttribute& mapTo(double& x, double init = 0.0); // Map to a double.
- ConfigurationAttribute& mapTo(bool& x, bool init = false); // Map to a boolean.
-
- // Attributes can have mnemonics just like elements.
-
- ConfigurationAttribute& Mnemonic(const char* name, const char* value); // Add a mnemonic using a c string.
- ConfigurationAttribute& Mnemonic(const char* name, const std::string value); // Add a mnemonic using c & c++ strings.
- ConfigurationAttribute& Mnemonic(const std::string name, const char* value); // Add a mnemonic using c++ & c strings.
- ConfigurationAttribute& Mnemonic(const std::string name, const std::string value); // Add a mnemonic using a c++ string.
-
- // Attributes participate in the Interprete() task just like elements.
-
- void initialize(); // Reset all translators to defaults.
- bool interpret(ConfigurationData& Data); // (re) Interpret this data.
-
- };
-
- //// Configuration Data ////////////////////////////////////////////////////////
- //
- // A ConfigurationData object holds on to the configuration source data and
- // provideds a place to log any information about how the configuration was
- // interpreted. It also creates and destroys a handy char[] to contain the
- // data. To make this beastie easier to handle, we use the Named Constructor
- // Idiom and hide the true constructor in the private section.
-
- class ConfigurationData { // Configuration Data Source
- private:
-
- char* myDataBuffer; // The actual data buffer.
- int myBufferSize; // Size of the current buffer.
- int myIndex; // The current interpretation index.
- int myLine; // Current line number.
-
- public:
-
- ConfigurationData(const char* FileName); // Constructor from c string file name.
- ConfigurationData(const std::string FileName); // Constructor from c++ string file name.
- ConfigurationData(const char* Data, int Length); // Raw constructor from text buffer.
-
- ~ConfigurationData(); // Destroys the internal buffer etc.
-
- char Data(int Index); // Returns char from Data[Index]
- int Index(); // Reads the current Index.
- int Index(int i); // Changes the current Index.
- int Line(); // Reads the current Line number.
- int addNewLines(int Count); // Increments the Line number.
-
- std::stringstream Log; // Convenient Interpret log.
-
- };
-
- //// Configuration Translator //////////////////////////////////////////////////
- //
- // A Translator converts the contents provided to it in string form into some
- // other data type. The object here is a prototype for that, followed by a
- // collection of the basic translators used for built-in mapTo()s.
-
- class ConfigurationTranslator { // Translators exist
- public:
- virtual ~ConfigurationTranslator(){}; // Stop No Virt Dtor warnings.
- virtual void translate(const char* Value) = 0; // Pure virtual translator.
- virtual void initialize() = 0; // Pure virtual initializer.
- };
-
- class StringTranslator : public ConfigurationTranslator {
- private:
- std::string& myVariable; // Variable to map.
- std::string myInitializer; // Initial/Default value.
-
- public:
- StringTranslator( // Construct this with
- std::string& Variable, // the variable to map,
- std::string Inititializer); // and the default value.
-
- void translate(const char* Value); // Provide a translation method.
- void initialize(); // Provide an initialization method.
- };
-
- class IntegerTranslator : public ConfigurationTranslator {
- private:
- int& myVariable; // Variable to map.
- int myInitializer; // Initial/Default value.
- int myRadix; // Radix for strtol()
-
- public:
- IntegerTranslator( // Construct this with
- int& Variable, // the variable to map,
- int Inititializer, // and the default value.
- int Radix); // For this one we also need a Radix.
-
- void translate(const char* Value); // Provide a translation method.
- void initialize(); // Provide an initialization method.
- };
-
- class DoubleTranslator : public ConfigurationTranslator {
- private:
- double& myVariable; // Variable to map.
- double myInitializer; // Initial/Default value.
-
- public:
- DoubleTranslator( // Construct this with
- double& Variable, // the variable to map,
- double Inititializer); // and the default value.
-
- void translate(const char* Value); // Provide a translation method.
- void initialize(); // Provide an initialization method.
- };
-
- class BoolTranslator : public ConfigurationTranslator {
- private:
- bool& myVariable; // Variable to map.
- bool myInitializer; // Initial/Default value.
-
- public:
- BoolTranslator( // Construct this with
- bool& Variable, // the variable to map,
- bool Inititializer); // and the default value.
-
- void translate(const char* Value); // Provide a translation method.
- void initialize(); // Provide an initialization method.
- };
-
- //// Configuration Mnemonic ////////////////////////////////////////////////////
- //
- // A Mnemonic allows the actual contents of an element or attribute to be
- // exchanged for a different "named" value to help eliminate "magic numbers"
- // and "secret codes" from configurations. One way this might be used is to
- // map an enumeration to the appropriate integer values, or things like YES and
- // NO to boolean true and false (respectively) when turning on/off program
- // options.
-
- class ConfigurationMnemonic { // Mnemonics
- private:
- std::string myName; // What is the Mnemonic?
- std::string myValue; // What is the translation?
-
- public:
- ConfigurationMnemonic(std::string Name, std::string Value); // To make one, provide both parts.
- bool test(std::string Name); // Test to see if this Mnemonic matches.
- std::string Value(); // If it does then we will need it's value.
- };
-
- //// Configurator //////////////////////////////////////////////////////////////
- //
- // A configurator is a "functor" or "closure" or "callback" that can be used to
- // support sophisticated interpretation options. The most basic and necessary
- // of these is support for list building. Consider an object created to contain
- // a list of records where each record might be represented as a collection of
- // attributes and elements. The object would have data elements mapped to the
- // attributes and elements in the configuration and then control elements which
- // are functors for initializing the list and storing new entries as they are
- // completed. The object here is a pure virtual prototype.
-
- class Configurator { // Configurators exist
- public:
- virtual void operator()(ConfigurationElement& E, ConfigurationData& D) = 0; // Pure virtual configurator.
- virtual ~Configurator() {} // Virtual dtor keeps warnings away.
- };
-
- //// Utilities /////////////////////////////////////////////////////////////////
-
- // SetTrueOnComplete Configurator //////////////////////////////////////////////
-
- class ConfiguratorSetTrueOnComplete : public Configurator { // Configurator set's a boolean true.
- private:
- bool* myBoolean; // The boolean to set.
- public:
- ConfiguratorSetTrueOnComplete(); // Must init to NULL for safety.
- void setup(bool& Target); // Link to the target boolean.
-
- void operator()(ConfigurationElement& E, ConfigurationData& D); // Handle the operation.
- };
-
- } // End namespace codedweller
|