| // base64codec.cpp | // base64codec.cpp | ||||
| // Copyright (C) 2006 - 2009 MicroNeil Research Corporation | |||||
| // See base64codec.hpp | |||||
| //typedef vector<char> base64codec_buffer; | |||||
| //typedef vector<char>::iterator base64codec_iterator; | |||||
| // | |||||
| // Copyright (C) 2004-2020 MicroNeil Research Corporation. | |||||
| // | |||||
| // This software is released under the MIT license. See LICENSE.TXT. | |||||
| #include "base64codec.hpp" | #include "base64codec.hpp" | ||||
| namespace base64codec { | |||||
| namespace codedweller { | |||||
| const static char base64encode[65] = // Base64 encoding characters. | const static char base64encode[65] = // Base64 encoding characters. | ||||
| "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; | ||||
| XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX // F | XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX // F | ||||
| }; | }; | ||||
| } // End namespace base64codec | |||||
| using namespace base64codec; | |||||
| //// to_base64 ///////////////////////////////////////////////////////////////// | //// to_base64 ///////////////////////////////////////////////////////////////// | ||||
| void to_base64::convert(const unsigned char* bfr, const int len) { // Converts from a char buffer. | void to_base64::convert(const unsigned char* bfr, const int len) { // Converts from a char buffer. | ||||
| BadConversion = false; // If we get here we've done good. | BadConversion = false; // If we get here we've done good. | ||||
| } | } | ||||
| to_base64::to_base64(const vector<unsigned char>& bfr) : // Converts from a base64buffer. | |||||
| to_base64::to_base64(const std::vector<unsigned char>& bfr) : // Converts from a base64buffer. | |||||
| BadConversion(true) { // No conversion yet ;-) | BadConversion(true) { // No conversion yet ;-) | ||||
| convert(&bfr[0], bfr.size()); // Recast the pointer and do it. | convert(&bfr[0], bfr.size()); // Recast the pointer and do it. | ||||
| } | } | ||||
| to_base64::to_base64(const vector<char>& bfr) : // Converts from a base64codec buffer. | |||||
| to_base64::to_base64(const std::vector<char>& bfr) : // Converts from a base64codec buffer. | |||||
| BadConversion(true) { // No conversion yet ;-) | BadConversion(true) { // No conversion yet ;-) | ||||
| convert(reinterpret_cast<const unsigned char*>(&bfr[0]), bfr.size()); // Do this to get it done. | convert(reinterpret_cast<const unsigned char*>(&bfr[0]), bfr.size()); // Do this to get it done. | ||||
| } | } | ||||
| convert(reinterpret_cast<const unsigned char*>(bfr), len); // Do this to get it done. | convert(reinterpret_cast<const unsigned char*>(bfr), len); // Do this to get it done. | ||||
| } | } | ||||
| to_base64::to_base64(const string& s) : // Converts from a c++ string. | |||||
| to_base64::to_base64(const std::string& s) : // Converts from a c++ string. | |||||
| BadConversion(true) { // No conversion yet ;-) | BadConversion(true) { // No conversion yet ;-) | ||||
| convert(reinterpret_cast<const unsigned char*>(s.c_str()), s.length()); // Do this to get it done. | convert(reinterpret_cast<const unsigned char*>(s.c_str()), s.length()); // Do this to get it done. | ||||
| } | } | ||||
| BadConversion = false; // If we get here we did ok. | BadConversion = false; // If we get here we did ok. | ||||
| } | } | ||||
| from_base64::from_base64(const vector<unsigned char>& bfr) : // Converts from a base64buffer. | |||||
| from_base64::from_base64(const std::vector<unsigned char>& bfr) : // Converts from a base64buffer. | |||||
| BadConversion(true) { // It's bad until we've done it. | BadConversion(true) { // It's bad until we've done it. | ||||
| convert(&bfr[0], bfr.size()); // Recast the pointer and do it. | convert(&bfr[0], bfr.size()); // Recast the pointer and do it. | ||||
| } | } | ||||
| from_base64::from_base64(const vector<char>& bfr) : // Converts from a buffer. | |||||
| from_base64::from_base64(const std::vector<char>& bfr) : // Converts from a buffer. | |||||
| BadConversion(true) { // It's bad until we've done it. | BadConversion(true) { // It's bad until we've done it. | ||||
| convert(reinterpret_cast<const unsigned char*>(&bfr[0]), bfr.size()); // This is how we do it. | convert(reinterpret_cast<const unsigned char*>(&bfr[0]), bfr.size()); // This is how we do it. | ||||
| } | } | ||||
| from_base64::from_base64(const string& s) : // Converts from a c++ string. | |||||
| from_base64::from_base64(const std::string& s) : // Converts from a c++ string. | |||||
| BadConversion(true) { // It's bad until we've done it. | BadConversion(true) { // It's bad until we've done it. | ||||
| convert(reinterpret_cast<const unsigned char*>(s.c_str()), s.length()); // This is how we do it. | convert(reinterpret_cast<const unsigned char*>(s.c_str()), s.length()); // This is how we do it. | ||||
| } | } | ||||
| return BadConversion; | return BadConversion; | ||||
| } | } | ||||
| } // end namespace codedweller |
| // base64codec.hpp | // base64codec.hpp | ||||
| // Copyright (C) 2006 - 2009 MicroNeil Research Corporation | |||||
| // BASE64 encoder decoder objects extending vectors | |||||
| // | |||||
| // Copyright (C) 2004-2020 MicroNeil Research Corporation. | |||||
| // | |||||
| // This software is released under the MIT license. See LICENSE.TXT. | |||||
| // | |||||
| // Tools for encoding and decoding base64 data. | |||||
| #ifndef base64codec_included | |||||
| #define base64codec_included | |||||
| #pragma once | |||||
| #include <vector> | #include <vector> | ||||
| #include <cstring> | #include <cstring> | ||||
| #include <string> | #include <string> | ||||
| using namespace std; | |||||
| namespace codedweller { | |||||
| typedef vector<unsigned char> base64buffer; | |||||
| typedef std::vector<unsigned char> base64buffer; | |||||
| class to_base64 : public base64buffer { // Converts binary data to base 64. | class to_base64 : public base64buffer { // Converts binary data to base 64. | ||||
| private: | private: | ||||
| void convert(const unsigned char* bfr, const int len); // Does the actual work. | void convert(const unsigned char* bfr, const int len); // Does the actual work. | ||||
| public: | public: | ||||
| to_base64(const vector<unsigned char>& bfr); // Converts from a base64buffer. | |||||
| to_base64(const vector<char>& bfr); // Converts from a buffer. | |||||
| to_base64(const string& s); // Converts from a c++ string. | |||||
| to_base64(const std::vector<unsigned char>& bfr); // Converts from a base64buffer. | |||||
| to_base64(const std::vector<char>& bfr); // Converts from a buffer. | |||||
| to_base64(const std::string& s); // Converts from a c++ string. | |||||
| to_base64(const char* s); // Converts from a c string. | to_base64(const char* s); // Converts from a c string. | ||||
| to_base64(const unsigned char* bfr, const int len); // Converts from a uchar buffer. | to_base64(const unsigned char* bfr, const int len); // Converts from a uchar buffer. | ||||
| to_base64(const char* bfr, const int len); // Converts from a char buffer. | to_base64(const char* bfr, const int len); // Converts from a char buffer. | ||||
| void convert(const unsigned char* bfr, const int len); // Does the actual work. | void convert(const unsigned char* bfr, const int len); // Does the actual work. | ||||
| public: | public: | ||||
| from_base64(const vector<unsigned char>& bfr); // Converts from a base64buffer. | |||||
| from_base64(const vector<char>& bfr); // Converts from a buffer. | |||||
| from_base64(const string& s); // Converts from a c++ string. | |||||
| from_base64(const std::vector<unsigned char>& bfr); // Converts from a base64buffer. | |||||
| from_base64(const std::vector<char>& bfr); // Converts from a buffer. | |||||
| from_base64(const std::string& s); // Converts from a c++ string. | |||||
| from_base64(const char*); // Converts from a c_string. | from_base64(const char*); // Converts from a c_string. | ||||
| bool Bad(); // True if conversion wasn't complete. | bool Bad(); // True if conversion wasn't complete. | ||||
| }; | }; | ||||
| #endif | |||||
| } |
| // configuration.cpp | // configuration.cpp | ||||
| // | // | ||||
| // (C) 2006 - 2009 MicroNeil Research Corporation. | |||||
| // Copyright (C) 2004-2020 MicroNeil Research Corporation. | |||||
| // | // | ||||
| // This program is part of the MicroNeil Research Open Library Project. For | |||||
| // more information go to http://www.microneil.com/OpenLibrary/index.html | |||||
| // This software is released under the MIT license. See LICENSE.TXT. | |||||
| // | // | ||||
| // This program is free software; you can redistribute it and/or modify it | |||||
| // under the terms of the GNU General Public License as published by the | |||||
| // Free Software Foundation; either version 2 of the License, or (at your | |||||
| // option) any later version. | |||||
| // | |||||
| // This program is distributed in the hope that it will be useful, but WITHOUT | |||||
| // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |||||
| // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |||||
| // more details. | |||||
| // | |||||
| // You should have received a copy of the GNU General Public License along with | |||||
| // this program; if not, write to the Free Software Foundation, Inc., 59 Temple | |||||
| // Place, Suite 330, Boston, MA 02111-1307 USA | |||||
| // See configuration.hpp for details | |||||
| // Tools for efficiently parsing XML, usually in configuration files. | |||||
| #include "configuration.hpp" | #include "configuration.hpp" | ||||
| using namespace std; | |||||
| namespace codedweller { | |||||
| //// Configuration Element ///////////////////////////////////////////////////// | |||||
| ConfigurationElement::ConfigurationElement(const char* Name) : // Construct with a cstring. | |||||
| myName(std::string(Name)), | |||||
| myParent(NULL), | |||||
| myLine(0), | |||||
| myIndex(0), | |||||
| myLength(0), | |||||
| myCleanFlag(true), | |||||
| myInitOnInterpretFlag(false) { | |||||
| } | |||||
| ConfigurationElement::ConfigurationElement(const std::string Name) : // Construct with a c++ string. | |||||
| myName(Name), | |||||
| myParent(NULL), | |||||
| myLine(0), | |||||
| myIndex(0), | |||||
| myLength(0), | |||||
| myCleanFlag(true), | |||||
| myInitOnInterpretFlag(false) { | |||||
| } | |||||
| ConfigurationElement::ConfigurationElement( // Construct sub element w/ cstring. | |||||
| const char* Name, | |||||
| ConfigurationElement& Parent) : | |||||
| myName(std::string(Name)), | |||||
| myParent(&Parent), | |||||
| myLine(0), | |||||
| myIndex(0), | |||||
| myLength(0), | |||||
| myCleanFlag(true), | |||||
| myInitOnInterpretFlag(false) { | |||||
| } | |||||
| ConfigurationElement::ConfigurationElement( // Construct sub element w/ string. | |||||
| const std::string Name, | |||||
| ConfigurationElement& Parent) : | |||||
| myName(Name), | |||||
| myParent(&Parent), | |||||
| myLine(0), | |||||
| myIndex(0), | |||||
| myLength(0), | |||||
| myCleanFlag(true), | |||||
| myInitOnInterpretFlag(false) { | |||||
| } | |||||
| std::string ConfigurationElement::Name() { return myName; } // Get the name of this element. | |||||
| ConfigurationElement& ConfigurationElement::Parent() { // Get the parrent of this element. | |||||
| if(NULL != myParent) { // If I have a parent | |||||
| return (*myParent); // then I dereference and return it. | |||||
| } // If I don't have a parent | |||||
| return (*this); // then I return myself. | |||||
| } | |||||
| ConfigurationElement& ConfigurationElement::Parent( // Set the parrent of this element. | |||||
| ConfigurationElement& Parent) { // Given this parent | |||||
| myParent = &Parent; // I take and store it's address | |||||
| return (*myParent); // then dereference and return it. | |||||
| } | |||||
| int ConfigurationElement::Line() { return myLine; } // Get the last line number. | |||||
| int ConfigurationElement::Index() { return myIndex; } // Get the last data position. | |||||
| int ConfigurationElement::Length() { return myLength; } // Get the last length. | |||||
| void ConfigurationElement::notifyDirty() { myCleanFlag = false; } // Attributes do this when they change. | |||||
| ConfigurationElement& ConfigurationElement::Element(const char* Name) { // Add a new sub element by c string name. | |||||
| return Element(std::string(Name)); // Use the string name version | |||||
| } | |||||
| ConfigurationElement& ConfigurationElement::Element(const std::string Name) { // Add a new sub element by c++ string name. | |||||
| ConfigurationElement* N = new ConfigurationElement( // Create a new Element with the | |||||
| Name, // name provided and | |||||
| (*this)); // myself as the parent. | |||||
| myElements.push_back(N); // Add it to the list. | |||||
| return (*N); // Return the new element. | |||||
| } | |||||
| ConfigurationElement& ConfigurationElement::Element( // Mapping factory for convenience, | |||||
| const char* Name, // requires a name, of course, | |||||
| ConfigurationTranslator& newTranslator) { // Add a Translator to this element. | |||||
| return Element(std::string(Name), newTranslator); // Use the string name version | |||||
| } | |||||
| ConfigurationElement& ConfigurationElement::Element( // Mapping factory for convenience, | |||||
| const char* Name, // requires a name, of course, | |||||
| std::string& x, std::string init) { // Map to a string. | |||||
| return Element(std::string(Name), x, init); // Use the string name version | |||||
| } | |||||
| ConfigurationElement& ConfigurationElement::Element( // Mapping factory for convenience, | |||||
| const char* Name, // requires a name, of course, | |||||
| int& x, int init, int radix) { // Map to an int. | |||||
| return Element(std::string(Name), x, init, radix); // Use the string name version | |||||
| } | |||||
| ConfigurationElement& ConfigurationElement::Element( // Mapping factory for convenience, | |||||
| const char* Name, // requires a name, of course, | |||||
| double& x, double init) { // Map to a double. | |||||
| return Element(std::string(Name), x, init); // Use the string name version | |||||
| } | |||||
| ConfigurationElement& ConfigurationElement::Element( // Mapping factory for convenience, | |||||
| const char* Name, // requires a name, of course, | |||||
| bool& x, bool init) { // Map to a boolean. | |||||
| return Element(std::string(Name), x, init); // Use the string name version | |||||
| } | |||||
| ConfigurationElement& ConfigurationElement::End() { // Return this element's parent. | |||||
| return Parent(); // Borrow Parent() | |||||
| } | |||||
| ConfigurationElement& ConfigurationElement::End(const char* Name) { // Check the name and return the parent | |||||
| return End(std::string(Name)); // Borrow End(string) | |||||
| } | |||||
| ConfigurationElement& ConfigurationElement::End(const std::string Name) { // if the name is correct - or throw! | |||||
| if(0 != Name.compare(myName)) { // If Name is not myName | |||||
| throw EndNameDoesNotMatch(); // throw an exception! | |||||
| } // If the names match then | |||||
| return Parent(); // return the parent. | |||||
| } | |||||
| ConfigurationAttribute& ConfigurationElement::Attribute( // Add an attribute using a cstring. | |||||
| const char* Name) { // Given this cstring name | |||||
| return Attribute(std::string(Name)); // Convert it to a string and borrow | |||||
| } // Attribute(string) | |||||
| ConfigurationAttribute& ConfigurationElement::Attribute( // Mapping factory for convenience, | |||||
| const char* Name, // requires a name, of course, | |||||
| ConfigurationTranslator& newTranslator) { // Add a Translator to this element. | |||||
| return Attribute(std::string(Name), newTranslator); // Borrow the string name version | |||||
| } | |||||
| ConfigurationAttribute& ConfigurationElement::Attribute( // Mapping factory for convenience, | |||||
| const char* Name, // requires a name, of course, | |||||
| std::string& x, std::string init) { // Map to a string. | |||||
| return Attribute(std::string(Name), x, init); // Borrow the string name version | |||||
| } | |||||
| ConfigurationAttribute& ConfigurationElement::Attribute( // Mapping factory for convenience, | |||||
| const char* Name, // requires a name, of course, | |||||
| int& x, int init, int radix) { // Map to an int. | |||||
| return Attribute(std::string(Name), x, init); // Borrow the string name version | |||||
| } | |||||
| ConfigurationAttribute& ConfigurationElement::Attribute( // Mapping factory for convenience, | |||||
| const char* Name, // requires a name, of course, | |||||
| double& x, double init) { // Map to a double. | |||||
| return Attribute(std::string(Name), x, init); // Borrow the string name version | |||||
| } | |||||
| ConfigurationAttribute& ConfigurationElement::Attribute( // Mapping factory for convenience, | |||||
| const char* Name, // requires a name, of course, | |||||
| bool& x, bool init) { // Map to a boolean. | |||||
| return Attribute(std::string(Name), x, init); // Borrow the string name version | |||||
| } | |||||
| ConfigurationElement& ConfigurationElement::setInitOnInterpret() { // Set the init on interpret flag. | |||||
| myInitOnInterpretFlag = true; // Set the flag. | |||||
| return(*this); // Dereference and return self. | |||||
| } | |||||
| ConfigurationElement& ConfigurationElement::atStartCall( // Add an atStart call-back. | |||||
| Configurator& Functor) { // Given this Functor, | |||||
| myStartConfigurators.push_back(&Functor); // add it to my atStart list then | |||||
| return(*this); // dereference and return myself. | |||||
| } | |||||
| ConfigurationElement& ConfigurationElement::atEndCall( // Add an atEnd call-back. | |||||
| Configurator& Functor) { // Given this Functor, | |||||
| myEndConfigurators.push_back(&Functor); // add it to my atEnd list then | |||||
| return(*this); // dereference and return myself. | |||||
| } | |||||
| ConfigurationElement& ConfigurationElement::Mnemonic( // Add a mnemonic using c strings. | |||||
| const char* name, const char* value) { // Given char* and char* | |||||
| return Mnemonic(std::string(name), std::string(value)); // make strings and borrow that method. | |||||
| } | |||||
| ConfigurationElement& ConfigurationElement::Mnemonic( // Add a mnemonic using mixed strings. | |||||
| const char* name, const std::string value) { // Given char* and string | |||||
| return Mnemonic(std::string(name), value); // make strings and borrow that method. | |||||
| } | |||||
| ConfigurationElement& ConfigurationElement::Mnemonic( // Add a mnemonic using mixed strings. | |||||
| const std::string name, const char* value) { // Given string and char* | |||||
| return Mnemonic(name, std::string(value)); // make strings and borrow that method. | |||||
| } | |||||
| ConfigurationElement& ConfigurationElement::Mnemonic( // Add a mnemonic using c++ strings. | |||||
| const std::string name, const std::string value) { // Givent string and string | |||||
| ConfigurationMnemonic* N = // Create a new Mnemonic | |||||
| new ConfigurationMnemonic(name, value); // using the values provided, | |||||
| myMnemonics.push_back(N); // add it to my list, then | |||||
| return(*this); // dereference and return myself. | |||||
| } | |||||
| //// Configuration Attribute /////////////////////////////////////////////////// | |||||
| ConfigurationAttribute::ConfigurationAttribute( // Attributes are constructed with a | |||||
| const char* Name, ConfigurationElement& Parent) : // Name and a Parent. | |||||
| myName(std::string(Name)), // We convert the name to a string. | |||||
| myParent(Parent), // We just grab the parent. | |||||
| myLine(0), // Everything else gets zeroed. | |||||
| myIndex(0), | |||||
| myLength(0) { | |||||
| } | |||||
| ConfigurationAttribute::ConfigurationAttribute( // Attributes are constrictued with a | |||||
| const std::string Name, ConfigurationElement& Parent) : // Name and a Parent. | |||||
| myName(Name), // We grab them and zero the rest. | |||||
| myParent(Parent), | |||||
| myLine(0), | |||||
| myIndex(0), | |||||
| myLength(0) { | |||||
| } | |||||
| std::string ConfigurationAttribute::Name() { // Get the name of this attribute. | |||||
| return myName; | |||||
| } | |||||
| ConfigurationElement& ConfigurationAttribute::Parent() { // Get the parent of this attribute. | |||||
| return myParent; | |||||
| } | |||||
| int ConfigurationAttribute::Line() { // Get the last line number. | |||||
| return myLine; | |||||
| } | |||||
| int ConfigurationAttribute::Index() { // Get the last data position. | |||||
| return myIndex; | |||||
| } | |||||
| int ConfigurationAttribute::Length() { // Get the last length. | |||||
| return myLength; | |||||
| } | |||||
| ConfigurationElement& ConfigurationAttribute::Element( // Add a new sub element by c string name. | |||||
| const char* Name) { | |||||
| return myParent.Element(Name); | |||||
| } | |||||
| ConfigurationElement& ConfigurationAttribute::Element( // Add a new sub element by c++ string name. | |||||
| const std::string Name) { | |||||
| return myParent.Element(Name); | |||||
| } | |||||
| ConfigurationElement& ConfigurationAttribute::Element( // Mapping factory for convenience, | |||||
| const char* Name, // requires a name, of course, | |||||
| ConfigurationTranslator& newTranslator) { // Add a Translator to this element. | |||||
| return myParent.Element(Name, newTranslator); | |||||
| } | |||||
| ConfigurationElement& ConfigurationAttribute::Element( // Mapping factory for convenience, | |||||
| const char* Name, // requires a name, of course, | |||||
| std::string& x, std::string init) { // Map to a string. | |||||
| return myParent.Element(Name, x, init); | |||||
| } | |||||
| ConfigurationElement& ConfigurationAttribute::Element( // Mapping factory for convenience, | |||||
| const char* Name, // requires a name, of course, | |||||
| int& x, int init, int radix) { // Map to an int. | |||||
| return myParent.Element(Name, x, init, radix); | |||||
| } | |||||
| ConfigurationElement& ConfigurationAttribute::Element( // Mapping factory for convenience, | |||||
| const char* Name, // requires a name, of course, | |||||
| double& x, double init) { // Map to a double. | |||||
| return myParent.Element(Name, x, init); | |||||
| } | |||||
| ConfigurationElement& ConfigurationAttribute::Element( // Mapping factory for convenience, | |||||
| const char* Name, // requires a name, of course, | |||||
| bool& x, bool init) { // Map to a boolean. | |||||
| return myParent.Element(Name, x, init); | |||||
| } | |||||
| ConfigurationElement& ConfigurationAttribute::Element( // Mapping factory for convenience, | |||||
| const std::string Name, // requires a name, of course, | |||||
| ConfigurationTranslator& newTranslator) { // Add a Translator to this element. | |||||
| return myParent.Element(Name, newTranslator); | |||||
| } | |||||
| ConfigurationElement& ConfigurationAttribute::Element( // Mapping factory for convenience, | |||||
| const std::string Name, // requires a name, of course, | |||||
| std::string& x, std::string init) { // Map to a string. | |||||
| return myParent.Element(Name, x, init); | |||||
| } | |||||
| ConfigurationElement& ConfigurationAttribute::Element( // Mapping factory for convenience, | |||||
| const std::string Name, // requires a name, of course, | |||||
| int& x, int init, int radix) { // Map to an int. | |||||
| return myParent.Element(Name, x, init, radix); | |||||
| } | |||||
| ConfigurationElement& ConfigurationAttribute::Element( // Mapping factory for convenience, | |||||
| const std::string Name, // requires a name, of course, | |||||
| double& x, double init) { // Map to a double. | |||||
| return myParent.Element(Name, x, init); | |||||
| } | |||||
| ConfigurationElement& ConfigurationAttribute::Element( // Mapping factory for convenience, | |||||
| const std::string Name, // requires a name, of course, | |||||
| bool& x, bool init) { // Map to a boolean. | |||||
| return myParent.Element(Name, x, init); | |||||
| } | |||||
| ConfigurationElement& ConfigurationAttribute::End() { // Return this element's parent. | |||||
| return myParent.End(); | |||||
| } | |||||
| ConfigurationElement& ConfigurationAttribute::End(const char* Name) { // Check the name and return the parent | |||||
| return myParent.End(Name); | |||||
| } | |||||
| ConfigurationElement& ConfigurationAttribute::End(const std::string Name) { // if the name is correct - or throw! | |||||
| return myParent.End(Name); | |||||
| } | |||||
| ConfigurationAttribute& ConfigurationAttribute::Attribute( // Add an attribute using a cstring. | |||||
| const char* Name) { | |||||
| return myParent.Attribute(Name); | |||||
| } | |||||
| ConfigurationAttribute& ConfigurationAttribute::Attribute( // Add an attribute using a c++ string. | |||||
| const std::string Name) { | |||||
| return myParent.Attribute(Name); | |||||
| } | |||||
| ConfigurationAttribute& ConfigurationAttribute::Attribute( // Mapping factory for convenience, | |||||
| const char* Name, // requires a name, of course, | |||||
| ConfigurationTranslator& newTranslator) { // Add a Translator to this element. | |||||
| return myParent.Attribute(Name, newTranslator); | |||||
| } | |||||
| ConfigurationAttribute& ConfigurationAttribute::Attribute( // Mapping factory for convenience, | |||||
| const char* Name, // requires a name, of course, | |||||
| std::string& x, std::string init) { // Map to a string. | |||||
| return myParent.Attribute(Name, x, init); | |||||
| } | |||||
| ConfigurationAttribute& ConfigurationAttribute::Attribute( // Mapping factory for convenience, | |||||
| const char* Name, // requires a name, of course, | |||||
| int& x, int init, int radix) { // Map to an int. | |||||
| return myParent.Attribute(Name, x, init, radix); | |||||
| } | |||||
| ConfigurationAttribute& ConfigurationAttribute::Attribute( // Mapping factory for convenience, | |||||
| const char* Name, // requires a name, of course, | |||||
| double& x, double init) { // Map to a double. | |||||
| return myParent.Attribute(Name, x, init); | |||||
| } | |||||
| ConfigurationAttribute& ConfigurationAttribute::Attribute( // Mapping factory for convenience, | |||||
| const char* Name, // requires a name, of course, | |||||
| bool& x, bool init) { // Map to a boolean. | |||||
| return myParent.Attribute(Name, x, init); | |||||
| } | |||||
| ConfigurationAttribute& ConfigurationAttribute::Attribute( // Mapping factory for convenience, | |||||
| const std::string Name, // requires a name, of course, | |||||
| ConfigurationTranslator& newTranslator) { // Add a Translator to this element. | |||||
| return myParent.Attribute(Name, newTranslator); | |||||
| } | |||||
| ConfigurationAttribute& ConfigurationAttribute::Attribute( // Mapping factory for convenience, | |||||
| const std::string Name, // requires a name, of course, | |||||
| std::string& x, std::string init) { // Map to a string. | |||||
| return myParent.Attribute(Name, x, init); | |||||
| } | |||||
| ConfigurationAttribute& ConfigurationAttribute::Attribute( // Mapping factory for convenience, | |||||
| const std::string Name, // requires a name, of course, | |||||
| int& x, int init, int radix) { // Map to an int. | |||||
| return myParent.Attribute(Name, x, init, radix); | |||||
| } | |||||
| ConfigurationAttribute& ConfigurationAttribute::Attribute( // Mapping factory for convenience, | |||||
| const std::string Name, // requires a name, of course, | |||||
| double& x, double init) { // Map to a double. | |||||
| return myParent.Attribute(Name, x, init); | |||||
| } | |||||
| ConfigurationAttribute& ConfigurationAttribute::Attribute( // Mapping factory for convenience, | |||||
| const std::string Name, // requires a name, of course, | |||||
| bool& x, bool init) { // Map to a boolean. | |||||
| return myParent.Attribute(Name, x, init); | |||||
| } | |||||
| ConfigurationElement& ConfigurationAttribute::setInitOnInterpret() { // Set the init on interpret flag. | |||||
| return myParent.setInitOnInterpret(); | |||||
| } | |||||
| ConfigurationElement& ConfigurationAttribute::atStartCall( // Add an atStart call-back to this element. | |||||
| Configurator& Functor) { | |||||
| return myParent.atStartCall(Functor); | |||||
| } | |||||
| ConfigurationElement& ConfigurationAttribute::atEndCall( // Add an atEnd call-back to this element. | |||||
| Configurator& Functor) { | |||||
| return myParent.atEndCall(Functor); | |||||
| } | |||||
| ConfigurationAttribute& ConfigurationAttribute::Mnemonic( // Add a mnemonic using c strings. | |||||
| const char* name, const char* value) { // Given char* and char* | |||||
| return Mnemonic(std::string(name), std::string(value)); // make strings and borrow that method. | |||||
| } | |||||
| ConfigurationAttribute& ConfigurationAttribute::Mnemonic( // Add a mnemonic using mixed strings. | |||||
| const char* name, const std::string value) { // Given char* and string | |||||
| return Mnemonic(std::string(name), value); // make strings and borrow that method. | |||||
| } | |||||
| ConfigurationAttribute& ConfigurationAttribute::Mnemonic( // Add a mnemonic using mixed strings. | |||||
| const std::string name, const char* value) { // Given string and char* | |||||
| return Mnemonic(name, std::string(value)); // make strings and borrow that method. | |||||
| } | |||||
| ConfigurationAttribute& ConfigurationAttribute::Mnemonic( // Add a mnemonic using c++ strings. | |||||
| const std::string name, const std::string value) { // Givent string and string | |||||
| ConfigurationMnemonic* N = // Create a new Mnemonic | |||||
| new ConfigurationMnemonic(name, value); // using the values provided, | |||||
| myMnemonics.push_back(N); // add it to my list, then | |||||
| return(*this); // dereference and return myself. | |||||
| } | |||||
| //// Configuration Data //////////////////////////////////////////////////////// | |||||
| char ConfigurationData::Data(int Index) { // Returns char from Data[Index] | |||||
| if(0 > Index || Index >= myBufferSize) { // Check that index is in range | |||||
| return 0; // and return 0 if it is not. | |||||
| } // If Index is within range then | |||||
| return myDataBuffer[Index]; // return the byte requested. | |||||
| } | |||||
| int ConfigurationData::Index() { // Reads the current Index. | |||||
| return myIndex; | |||||
| } | |||||
| int ConfigurationData::Index(int i) { // Changes the current Index. | |||||
| if(0 > i || i >= myBufferSize) { // If i is out of range then | |||||
| return myIndex; // return the current Index unchanged. | |||||
| } // If i is within range then | |||||
| myIndex = i; // change the Index to i and | |||||
| return myIndex; // return the changed Index. | |||||
| } | |||||
| int ConfigurationData::Line() { // Reads the current Line number. | |||||
| return myLine; | |||||
| } | |||||
| int ConfigurationData::addNewLines(int Count) { // Increments the Line number. | |||||
| myLine += Count; // Add the number of new lines. | |||||
| return myLine; // Return the current Line number. | |||||
| } | |||||
| //// Configuration Translator ////////////////////////////////////////////////// | |||||
| StringTranslator::StringTranslator( // Construct this with | |||||
| std::string& Variable, // the variable to map, | |||||
| std::string Initializer) : // and the default value. | |||||
| myVariable(Variable), | |||||
| myInitializer(Initializer) { | |||||
| } | |||||
| void StringTranslator::translate(const char* Value) { // Provide a translation method. | |||||
| myVariable = std::string(Value); // String to String = simple copy. | |||||
| } | |||||
| void StringTranslator::initialize() { // Provide an initialization method. | |||||
| myVariable = myInitializer; // Revert to the initializer value. | |||||
| } | |||||
| IntegerTranslator::IntegerTranslator( // Construct this with | |||||
| int& Variable, // the variable to map, | |||||
| int Initializer, // and the default value. | |||||
| int Radix) : // For this one we also need a Radix. | |||||
| myVariable(Variable), | |||||
| myInitializer(Initializer), | |||||
| myRadix(Radix) { | |||||
| } | |||||
| void IntegerTranslator::translate(const char* Value) { // Provide a translation method. | |||||
| char* dummy; // Throw away ptr for strtol(). | |||||
| myVariable = strtol(Value, &dummy, myRadix); // Convert the string w/ strtol(). | |||||
| } | |||||
| void IntegerTranslator::initialize() { // Provide an initialization method. | |||||
| myVariable = myInitializer; // Revert to the initializer value. | |||||
| } | |||||
| DoubleTranslator::DoubleTranslator( // Construct this with | |||||
| double& Variable, // the variable to map, | |||||
| double Initializer) : // and the default value. | |||||
| myVariable(Variable), | |||||
| myInitializer(Initializer) { | |||||
| } | |||||
| void DoubleTranslator::translate(const char* Value) { // Provide a translation method. | |||||
| char* dummy; // Throw away ptr for strtod(). | |||||
| myVariable = strtod(Value, &dummy); // Convert the string w/ strtod(). | |||||
| } | |||||
| void DoubleTranslator::initialize() { // Provide an initialization method. | |||||
| myVariable = myInitializer; // Revert to the initializer value. | |||||
| } | |||||
| BoolTranslator::BoolTranslator( // Construct this with | |||||
| bool& Variable, // the variable to map, | |||||
| bool Initializer) : // and the default value. | |||||
| myVariable(Variable), | |||||
| myInitializer(Initializer) { | |||||
| } | |||||
| void BoolTranslator::translate(const char* Value) { // Provide a translation method. | |||||
| if( | |||||
| (0 == strcmp(Value,"on")) || | |||||
| (0 == strcmp(Value,"true")) || // on, true, yes, and 1 are | |||||
| (0 == strcmp(Value, "yes")) || // interpreted as a boolean true. | |||||
| (0 == strcmp(Value, "1")) | |||||
| ) { | |||||
| myVariable = true; | |||||
| } else { // Anything else is interpreted as | |||||
| myVariable = false; // boolean false. | |||||
| } | |||||
| } | |||||
| void BoolTranslator::initialize() { // Provide an initialization method. | |||||
| myVariable = myInitializer; // Revert to the initializer value. | |||||
| } | |||||
| //// Configuration Mnemonic //////////////////////////////////////////////////// | |||||
| ConfigurationMnemonic::ConfigurationMnemonic( // To make one, provide both parts. | |||||
| std::string Name, std::string Value) : | |||||
| myName(Name), | |||||
| myValue(Value) { | |||||
| } | |||||
| bool ConfigurationMnemonic::test(std::string Name) { // Test to see if this Mnemonic matches. | |||||
| return (0 == Name.compare(myName)); // Return true if Name and myName match. | |||||
| } | |||||
| std::string ConfigurationMnemonic::Value() { // If it does then we will need it's value. | |||||
| return myValue; | |||||
| } | |||||
| //// Helper functions ////////////////////////////////////////////////////////// | //// Helper functions ////////////////////////////////////////////////////////// | ||||
| // Delete my attributes | // Delete my attributes | ||||
| if(0 < myAttributes.size()) { // If we have attributes... | if(0 < myAttributes.size()) { // If we have attributes... | ||||
| list<ConfigurationAttribute*>::iterator iAttribute; // Iterate through our attributes list. | |||||
| std::list<ConfigurationAttribute*>::iterator iAttribute; // Iterate through our attributes list. | |||||
| iAttribute = myAttributes.begin(); // Start at the beginning and | iAttribute = myAttributes.begin(); // Start at the beginning and | ||||
| while(iAttribute != myAttributes.end()) { // loop through the whole list. | while(iAttribute != myAttributes.end()) { // loop through the whole list. | ||||
| delete (*iAttribute); // Delete each attribute | delete (*iAttribute); // Delete each attribute | ||||
| // Delete my sub-elements | // Delete my sub-elements | ||||
| if(0 < myElements.size()) { // If we have elements... | if(0 < myElements.size()) { // If we have elements... | ||||
| list<ConfigurationElement*>::iterator iElement; // Iterate through our elements list. | |||||
| std::list<ConfigurationElement*>::iterator iElement; // Iterate through our elements list. | |||||
| iElement = myElements.begin(); // Start at the beginning and | iElement = myElements.begin(); // Start at the beginning and | ||||
| while(iElement != myElements.end()) { // loop through the whole list. | while(iElement != myElements.end()) { // loop through the whole list. | ||||
| delete (*iElement); // Delete each element | delete (*iElement); // Delete each element | ||||
| // Delete my mnemonics | // Delete my mnemonics | ||||
| if(0 < myMnemonics.size()) { // If we have mnemonics... | if(0 < myMnemonics.size()) { // If we have mnemonics... | ||||
| list<ConfigurationMnemonic*>::iterator iMnemonic; // Iterate through our mnemonics list. | |||||
| std::list<ConfigurationMnemonic*>::iterator iMnemonic; // Iterate through our mnemonics list. | |||||
| iMnemonic = myMnemonics.begin(); // Start at the beginning and | iMnemonic = myMnemonics.begin(); // Start at the beginning and | ||||
| while(iMnemonic != myMnemonics.end()) { // loop through the whole list. | while(iMnemonic != myMnemonics.end()) { // loop through the whole list. | ||||
| delete (*iMnemonic); // Delete each mnemonic | delete (*iMnemonic); // Delete each mnemonic | ||||
| // Delete my translators | // Delete my translators | ||||
| if(0 < myTranslators.size()) { // If we have translators... | if(0 < myTranslators.size()) { // If we have translators... | ||||
| list<ConfigurationTranslator*>::iterator iTranslator; // Iterate through our translators list. | |||||
| std::list<ConfigurationTranslator*>::iterator iTranslator; // Iterate through our translators list. | |||||
| iTranslator = myTranslators.begin(); // Start at the beginning and | iTranslator = myTranslators.begin(); // Start at the beginning and | ||||
| while(iTranslator != myTranslators.end()) { // loop through the whole list. | while(iTranslator != myTranslators.end()) { // loop through the whole list. | ||||
| delete (*iTranslator); // Delete each translator | delete (*iTranslator); // Delete each translator | ||||
| } | } | ||||
| ConfigurationElement& ConfigurationElement::Element( // Mapping factory for convenience, | ConfigurationElement& ConfigurationElement::Element( // Mapping factory for convenience, | ||||
| const string Name, // requires a name, of course, | |||||
| const std::string Name, // requires a name, of course, | |||||
| ConfigurationTranslator& newTranslator) { // Add a Translator to this element. | ConfigurationTranslator& newTranslator) { // Add a Translator to this element. | ||||
| ConfigurationElement* N = new ConfigurationElement( // Create a new Element with the | ConfigurationElement* N = new ConfigurationElement( // Create a new Element with the | ||||
| } | } | ||||
| ConfigurationElement& ConfigurationElement::Element( // Mapping factory for convenience, | ConfigurationElement& ConfigurationElement::Element( // Mapping factory for convenience, | ||||
| const string Name, // requires a name, of course, | |||||
| string& x, string init) { // Map to a string. | |||||
| const std::string Name, // requires a name, of course, | |||||
| std::string& x, std::string init) { // Map to a string. | |||||
| ConfigurationElement* N = new ConfigurationElement( // Create a new Element with the | ConfigurationElement* N = new ConfigurationElement( // Create a new Element with the | ||||
| Name, // name provided and | Name, // name provided and | ||||
| } | } | ||||
| ConfigurationElement& ConfigurationElement::Element( // Mapping factory for convenience, | ConfigurationElement& ConfigurationElement::Element( // Mapping factory for convenience, | ||||
| const string Name, // requires a name, of course, | |||||
| const std::string Name, // requires a name, of course, | |||||
| int& x, int init, int radix) { // Map to an int. | int& x, int init, int radix) { // Map to an int. | ||||
| ConfigurationElement* N = new ConfigurationElement( // Create a new Element with the | ConfigurationElement* N = new ConfigurationElement( // Create a new Element with the | ||||
| } | } | ||||
| ConfigurationElement& ConfigurationElement::Element( // Mapping factory for convenience, | ConfigurationElement& ConfigurationElement::Element( // Mapping factory for convenience, | ||||
| const string Name, // requires a name, of course, | |||||
| const std::string Name, // requires a name, of course, | |||||
| double& x, double init) { // Map to a double. | double& x, double init) { // Map to a double. | ||||
| ConfigurationElement* N = new ConfigurationElement( // Create a new Element with the | ConfigurationElement* N = new ConfigurationElement( // Create a new Element with the | ||||
| } | } | ||||
| ConfigurationElement& ConfigurationElement::Element( // Mapping factory for convenience, | ConfigurationElement& ConfigurationElement::Element( // Mapping factory for convenience, | ||||
| const string Name, // requires a name, of course, | |||||
| const std::string Name, // requires a name, of course, | |||||
| bool& x, bool init) { // Map to a boolean. | bool& x, bool init) { // Map to a boolean. | ||||
| ConfigurationElement* N = new ConfigurationElement( // Create a new Element with the | ConfigurationElement* N = new ConfigurationElement( // Create a new Element with the | ||||
| return (*N); // Return the new element. | return (*N); // Return the new element. | ||||
| } | } | ||||
| ConfigurationAttribute& ConfigurationElement::Attribute(const string Name) { // Add an attribute using a c++ string. | |||||
| ConfigurationAttribute* N = // Create a new attribute by name and | |||||
| new ConfigurationAttribute(Name, (*this)); // provide myself as the parent. | |||||
| ConfigurationAttribute& ConfigurationElement::Attribute(const std::string Name) { // Add an attribute using a c++ string. | |||||
| ConfigurationAttribute* N = // Create a new attribute by name and | |||||
| new ConfigurationAttribute(Name, (*this)); // provide myself as the parent. | |||||
| myCleanFlag = false; // New attributes make us dirty. | myCleanFlag = false; // New attributes make us dirty. | ||||
| } | } | ||||
| ConfigurationAttribute& ConfigurationElement::Attribute( // Mapping factory for convenience, | ConfigurationAttribute& ConfigurationElement::Attribute( // Mapping factory for convenience, | ||||
| const string Name, // requires a name, of course, | |||||
| const std::string Name, // requires a name, of course, | |||||
| ConfigurationTranslator& newTranslator) { // Add a Translator to this element. | ConfigurationTranslator& newTranslator) { // Add a Translator to this element. | ||||
| myCleanFlag = false; // New attributes make us dirty. | myCleanFlag = false; // New attributes make us dirty. | ||||
| } | } | ||||
| ConfigurationAttribute& ConfigurationElement::Attribute( // Mapping factory for convenience, | ConfigurationAttribute& ConfigurationElement::Attribute( // Mapping factory for convenience, | ||||
| const string Name, // requires a name, of course, | |||||
| string& x, string init) { // Map to a string. | |||||
| const std::string Name, // requires a name, of course, | |||||
| std::string& x, std::string init) { // Map to a string. | |||||
| myCleanFlag = false; // New attributes make us dirty. | myCleanFlag = false; // New attributes make us dirty. | ||||
| } | } | ||||
| ConfigurationAttribute& ConfigurationElement::Attribute( // Mapping factory for convenience, | ConfigurationAttribute& ConfigurationElement::Attribute( // Mapping factory for convenience, | ||||
| const string Name, // requires a name, of course, | |||||
| const std::string Name, // requires a name, of course, | |||||
| int& x, int init, int radix) { // Map to an int. | int& x, int init, int radix) { // Map to an int. | ||||
| myCleanFlag = false; // New attributes make us dirty. | myCleanFlag = false; // New attributes make us dirty. | ||||
| } | } | ||||
| ConfigurationAttribute& ConfigurationElement::Attribute( // Mapping factory for convenience, | ConfigurationAttribute& ConfigurationElement::Attribute( // Mapping factory for convenience, | ||||
| const string Name, // requires a name, of course, | |||||
| const std::string Name, // requires a name, of course, | |||||
| double& x, double init) { // Map to a double. | double& x, double init) { // Map to a double. | ||||
| myCleanFlag = false; // New attributes make us dirty. | myCleanFlag = false; // New attributes make us dirty. | ||||
| } | } | ||||
| ConfigurationAttribute& ConfigurationElement::Attribute( // Mapping factory for convenience, | ConfigurationAttribute& ConfigurationElement::Attribute( // Mapping factory for convenience, | ||||
| const string Name, // requires a name, of course, | |||||
| const std::string Name, // requires a name, of course, | |||||
| bool& x, bool init) { // Map to a boolean. | bool& x, bool init) { // Map to a boolean. | ||||
| myCleanFlag = false; // New attributes make us dirty. | myCleanFlag = false; // New attributes make us dirty. | ||||
| } | } | ||||
| ConfigurationElement& ConfigurationElement::mapTo( // Map to a string. | ConfigurationElement& ConfigurationElement::mapTo( // Map to a string. | ||||
| string& x, string init) { // Given a string and init value, | |||||
| std::string& x, std::string init) { // Given a string and init value, | |||||
| ConfigurationTranslator* N = // create a new translator for it | ConfigurationTranslator* N = // create a new translator for it | ||||
| new StringTranslator(x, init); // with the values i'm given, | new StringTranslator(x, init); // with the values i'm given, | ||||
| myTranslators.push_back(N); // push it onto my list, then | myTranslators.push_back(N); // push it onto my list, then | ||||
| // Initialize the elements below me | // Initialize the elements below me | ||||
| if(0 < myElements.size()) { // If we have elements... | if(0 < myElements.size()) { // If we have elements... | ||||
| list<ConfigurationElement*>::iterator iElement; // Iterate through our elements list. | |||||
| std::list<ConfigurationElement*>::iterator iElement; // Iterate through our elements list. | |||||
| iElement = myElements.begin(); // Start at the beginning and | iElement = myElements.begin(); // Start at the beginning and | ||||
| while(iElement != myElements.end()) { // loop through the whole list. | while(iElement != myElements.end()) { // loop through the whole list. | ||||
| (*iElement)->initialize(); // Initialize each element | (*iElement)->initialize(); // Initialize each element | ||||
| // Initialize my own translators | // Initialize my own translators | ||||
| if(0 < myTranslators.size()) { // If we have translators... | if(0 < myTranslators.size()) { // If we have translators... | ||||
| list<ConfigurationTranslator*>::iterator iTranslator; // Iterate through our translators list. | |||||
| std::list<ConfigurationTranslator*>::iterator iTranslator; // Iterate through our translators list. | |||||
| iTranslator = myTranslators.begin(); // Start at the beginning and | iTranslator = myTranslators.begin(); // Start at the beginning and | ||||
| while(iTranslator != myTranslators.end()) { // loop through the whole list. | while(iTranslator != myTranslators.end()) { // loop through the whole list. | ||||
| (*iTranslator)->initialize(); // Initialize each translator | (*iTranslator)->initialize(); // Initialize each translator | ||||
| // Initialize my own attributes | // Initialize my own attributes | ||||
| if(0 < myAttributes.size()) { // If we have attributes... | if(0 < myAttributes.size()) { // If we have attributes... | ||||
| list<ConfigurationAttribute*>::iterator iAttribute; // Iterate through our attributes list. | |||||
| std::list<ConfigurationAttribute*>::iterator iAttribute; // Iterate through our attributes list. | |||||
| iAttribute = myAttributes.begin(); // Start at the beginning and | iAttribute = myAttributes.begin(); // Start at the beginning and | ||||
| while(iAttribute != myAttributes.end()) { // loop through the whole list. | while(iAttribute != myAttributes.end()) { // loop through the whole list. | ||||
| (*iAttribute)->initialize(); // Initialize each attribute | (*iAttribute)->initialize(); // Initialize each attribute | ||||
| } | } | ||||
| void ConfigurationElement::runStartConfigurators(ConfigurationData& D) { // Does what it says ;-) | void ConfigurationElement::runStartConfigurators(ConfigurationData& D) { // Does what it says ;-) | ||||
| list<Configurator*>::iterator iConfigurator; // Iterate through our Configurators list. | |||||
| std::list<Configurator*>::iterator iConfigurator; // Iterate through our Configurators list. | |||||
| iConfigurator = myStartConfigurators.begin(); // Start at the beginning and | iConfigurator = myStartConfigurators.begin(); // Start at the beginning and | ||||
| while(iConfigurator != myStartConfigurators.end()) { // loop through the whole list. | while(iConfigurator != myStartConfigurators.end()) { // loop through the whole list. | ||||
| (** iConfigurator)(*this, D); // Launch each configurator with self. | (** iConfigurator)(*this, D); // Launch each configurator with self. | ||||
| } | } | ||||
| void ConfigurationElement::runEndConfigurators(ConfigurationData& D) { // Does what it says ;-) | void ConfigurationElement::runEndConfigurators(ConfigurationData& D) { // Does what it says ;-) | ||||
| list<Configurator*>::iterator iConfigurator; // Iterate through our Configurators list. | |||||
| std::list<Configurator*>::iterator iConfigurator; // Iterate through our Configurators list. | |||||
| iConfigurator = myEndConfigurators.begin(); // Start at the beginning and | iConfigurator = myEndConfigurators.begin(); // Start at the beginning and | ||||
| while(iConfigurator != myEndConfigurators.end()) { // loop through the whole list. | while(iConfigurator != myEndConfigurators.end()) { // loop through the whole list. | ||||
| (** iConfigurator)(*this, D); // Launch each configurator with self. | (** iConfigurator)(*this, D); // Launch each configurator with self. | ||||
| if(isalpha(Data.Data(Index))) { // If it looks like an attribute... | if(isalpha(Data.Data(Index))) { // If it looks like an attribute... | ||||
| bool ParseHappened = false; // Start pessimistically at each pass. | bool ParseHappened = false; // Start pessimistically at each pass. | ||||
| list<ConfigurationAttribute*>::iterator iAttribute; // Iterate through our attributes list. | |||||
| std::list<ConfigurationAttribute*>::iterator iAttribute; // Iterate through our attributes list. | |||||
| iAttribute = myAttributes.begin(); // Start at the beginning and | iAttribute = myAttributes.begin(); // Start at the beginning and | ||||
| while(iAttribute != myAttributes.end()) { // loop through the whole list. | while(iAttribute != myAttributes.end()) { // loop through the whole list. | ||||
| ParseHappened = (* iAttribute)->interpret(Data); // Have each attribute interpret(Data) | ParseHappened = (* iAttribute)->interpret(Data); // Have each attribute interpret(Data) | ||||
| NewLines = 0; // Reset our new lines count. | NewLines = 0; // Reset our new lines count. | ||||
| if(0 < myElements.size()) { // If we have elements check them. | if(0 < myElements.size()) { // If we have elements check them. | ||||
| list<ConfigurationElement*>::iterator iElement; // Iterate through our elements list. | |||||
| std::list<ConfigurationElement*>::iterator iElement; // Iterate through our elements list. | |||||
| iElement = myElements.begin(); // Start at the beginning and | iElement = myElements.begin(); // Start at the beginning and | ||||
| while(iElement != myElements.end()) { // loop through the whole list. | while(iElement != myElements.end()) { // loop through the whole list. | ||||
| ConfigurationElement& doNode = **iElement; // Grab the element we're on. | ConfigurationElement& doNode = **iElement; // Grab the element we're on. | ||||
| // Create the Content buffer... | // Create the Content buffer... | ||||
| int BfrSize = Stopdex - Startdex +1; // How big a buffer do we need? | int BfrSize = Stopdex - Startdex +1; // How big a buffer do we need? | ||||
| vector<char> heapBfr(BfrSize,0); // Make one that size. | |||||
| std::vector<char> heapBfr(BfrSize,0); // Make one that size. | |||||
| char* Bfr = &heapBfr[0]; | char* Bfr = &heapBfr[0]; | ||||
| copyDataCountLines(Bfr, Data, Startdex, Stopdex); // Get our data and ignore our lines. | copyDataCountLines(Bfr, Data, Startdex, Stopdex); // Get our data and ignore our lines. | ||||
| // Translate our data by Mnemonic | // Translate our data by Mnemonic | ||||
| if(0 < myMnemonics.size()) { // If we have mnemonics... | if(0 < myMnemonics.size()) { // If we have mnemonics... | ||||
| list<ConfigurationMnemonic*>::iterator iMnemonic; // Iterate through our mnemonics list. | |||||
| std::list<ConfigurationMnemonic*>::iterator iMnemonic; // Iterate through our mnemonics list. | |||||
| iMnemonic = myMnemonics.begin(); // Start at the beginning and | iMnemonic = myMnemonics.begin(); // Start at the beginning and | ||||
| while(iMnemonic != myMnemonics.end()) { // loop through the whole list. | while(iMnemonic != myMnemonics.end()) { // loop through the whole list. | ||||
| if(true == ((*iMnemonic)->test(TranslationData))) { // Check to see if the mnemonic matches. | if(true == ((*iMnemonic)->test(TranslationData))) { // Check to see if the mnemonic matches. | ||||
| // Put our TranslationData through each Translator. | // Put our TranslationData through each Translator. | ||||
| list<ConfigurationTranslator*>::iterator iTranslator; // Iterate through our translators list. | |||||
| std::list<ConfigurationTranslator*>::iterator iTranslator; // Iterate through our translators list. | |||||
| iTranslator = myTranslators.begin(); // Start at the beginning and | iTranslator = myTranslators.begin(); // Start at the beginning and | ||||
| while(iTranslator != myTranslators.end()) { // loop through the whole list. | while(iTranslator != myTranslators.end()) { // loop through the whole list. | ||||
| (*iTranslator)->translate(TranslationData); // Pass the data to each one then | (*iTranslator)->translate(TranslationData); // Pass the data to each one then | ||||
| // Delete my mnemonics | // Delete my mnemonics | ||||
| if(0 < myMnemonics.size()) { // If we have mnemonics... | if(0 < myMnemonics.size()) { // If we have mnemonics... | ||||
| list<ConfigurationMnemonic*>::iterator iMnemonic; // Iterate through our mnemonics list. | |||||
| std::list<ConfigurationMnemonic*>::iterator iMnemonic; // Iterate through our mnemonics list. | |||||
| iMnemonic = myMnemonics.begin(); // Start at the beginning and | iMnemonic = myMnemonics.begin(); // Start at the beginning and | ||||
| while(iMnemonic != myMnemonics.end()) { // loop through the whole list. | while(iMnemonic != myMnemonics.end()) { // loop through the whole list. | ||||
| delete (*iMnemonic); // Delete each mnemonic | delete (*iMnemonic); // Delete each mnemonic | ||||
| // Delete my translators | // Delete my translators | ||||
| if(0 < myTranslators.size()) { // If we have translators... | if(0 < myTranslators.size()) { // If we have translators... | ||||
| list<ConfigurationTranslator*>::iterator iTranslator; // Iterate through our translators list. | |||||
| std::list<ConfigurationTranslator*>::iterator iTranslator; // Iterate through our translators list. | |||||
| iTranslator = myTranslators.begin(); // Start at the beginning and | iTranslator = myTranslators.begin(); // Start at the beginning and | ||||
| while(iTranslator != myTranslators.end()) { // loop through the whole list. | while(iTranslator != myTranslators.end()) { // loop through the whole list. | ||||
| delete (*iTranslator); // Delete each translator | delete (*iTranslator); // Delete each translator | ||||
| } | } | ||||
| ConfigurationAttribute& ConfigurationAttribute::mapTo( // Map to a string. | ConfigurationAttribute& ConfigurationAttribute::mapTo( // Map to a string. | ||||
| string& x, string init) { // Given a string and init value, | |||||
| std::string& x, std::string init) { // Given a string and init value, | |||||
| ConfigurationTranslator* N = // create a new translator for it | ConfigurationTranslator* N = // create a new translator for it | ||||
| new StringTranslator(x, init); // with the values i'm given, | new StringTranslator(x, init); // with the values i'm given, | ||||
| myTranslators.push_back(N); // push it onto my list, then | myTranslators.push_back(N); // push it onto my list, then | ||||
| void ConfigurationAttribute::initialize() { // Reset all translators to defaults. | void ConfigurationAttribute::initialize() { // Reset all translators to defaults. | ||||
| if(0 < myTranslators.size()) { // If we have translators... | if(0 < myTranslators.size()) { // If we have translators... | ||||
| list<ConfigurationTranslator*>::iterator iTranslator; // Iterate through our translators list. | |||||
| std::list<ConfigurationTranslator*>::iterator iTranslator; // Iterate through our translators list. | |||||
| iTranslator = myTranslators.begin(); // Start at the beginning and | iTranslator = myTranslators.begin(); // Start at the beginning and | ||||
| while(iTranslator != myTranslators.end()) { // loop through the whole list. | while(iTranslator != myTranslators.end()) { // loop through the whole list. | ||||
| (*iTranslator)->initialize(); // initialize each translator | (*iTranslator)->initialize(); // initialize each translator | ||||
| // Read our data. | // Read our data. | ||||
| int BfrSize = Stopdex - Startdex +1; // How big a buffer do we need? | int BfrSize = Stopdex - Startdex +1; // How big a buffer do we need? | ||||
| vector<char> heapBfr(BfrSize,0); // Make one that size. | |||||
| std::vector<char> heapBfr(BfrSize,0); // Make one that size. | |||||
| char* Bfr = &heapBfr[0]; | char* Bfr = &heapBfr[0]; | ||||
| NewLines += copyDataCountLines(Bfr, Data, Startdex, Stopdex); // Get our data and count our lines. | NewLines += copyDataCountLines(Bfr, Data, Startdex, Stopdex); // Get our data and count our lines. | ||||
| // Translate our data by Mnemonic | // Translate our data by Mnemonic | ||||
| if(0 < myMnemonics.size()) { // If we have mnemonics... | if(0 < myMnemonics.size()) { // If we have mnemonics... | ||||
| list<ConfigurationMnemonic*>::iterator iMnemonic; // Iterate through our mnemonics list. | |||||
| std::list<ConfigurationMnemonic*>::iterator iMnemonic; // Iterate through our mnemonics list. | |||||
| iMnemonic = myMnemonics.begin(); // Start at the beginning and | iMnemonic = myMnemonics.begin(); // Start at the beginning and | ||||
| while(iMnemonic != myMnemonics.end()) { // loop through the whole list. | while(iMnemonic != myMnemonics.end()) { // loop through the whole list. | ||||
| if(true == ((*iMnemonic)->test(TranslationData))){ // Check to see if the mnemonic matches. | if(true == ((*iMnemonic)->test(TranslationData))){ // Check to see if the mnemonic matches. | ||||
| // Put our TranslationData through each Translator. | // Put our TranslationData through each Translator. | ||||
| if(0 < myTranslators.size()) { // We'd better have translators! | if(0 < myTranslators.size()) { // We'd better have translators! | ||||
| list<ConfigurationTranslator*>::iterator iTranslator; // Iterate through our translators list. | |||||
| std::list<ConfigurationTranslator*>::iterator iTranslator; // Iterate through our translators list. | |||||
| iTranslator = myTranslators.begin(); // Start at the beginning and | iTranslator = myTranslators.begin(); // Start at the beginning and | ||||
| while(iTranslator != myTranslators.end()) { // loop through the whole list. | while(iTranslator != myTranslators.end()) { // loop through the whole list. | ||||
| (*iTranslator)->translate(TranslationData); // Pass the data to each one and | (*iTranslator)->translate(TranslationData); // Pass the data to each one and | ||||
| myIndex(0), // Our Index is zero | myIndex(0), // Our Index is zero | ||||
| myLine(1) { // We start on line 1 | myLine(1) { // We start on line 1 | ||||
| try { // Capture any throws. | try { // Capture any throws. | ||||
| ifstream CFGFile(FileName); // Open the file. | |||||
| CFGFile.seekg(0,ios::end); // Seek to the end | |||||
| std::ifstream CFGFile(FileName); // Open the file. | |||||
| CFGFile.seekg(0,std::ios::end); // Seek to the end | |||||
| myBufferSize = CFGFile.tellg(); // to find out what size it is. | myBufferSize = CFGFile.tellg(); // to find out what size it is. | ||||
| myDataBuffer = newCStringBuffer(myBufferSize); // Make a new buffer the right size. | myDataBuffer = newCStringBuffer(myBufferSize); // Make a new buffer the right size. | ||||
| CFGFile.seekg(0,ios::beg); // Seek to the beginning and | |||||
| CFGFile.seekg(0,std::ios::beg); // Seek to the beginning and | |||||
| CFGFile.read(myDataBuffer, myBufferSize); // read the file into the buffer. | CFGFile.read(myDataBuffer, myBufferSize); // read the file into the buffer. | ||||
| if(CFGFile.bad()) { // If the read failed, we're unusable! | if(CFGFile.bad()) { // If the read failed, we're unusable! | ||||
| delete[] myDataBuffer; // Delete the buffer | delete[] myDataBuffer; // Delete the buffer | ||||
| } // indicating there is no Data. | } // indicating there is no Data. | ||||
| } | } | ||||
| ConfigurationData::ConfigurationData(const string FileName) : // Raw constructor from file. | |||||
| ConfigurationData::ConfigurationData(const std::string FileName) : // Raw constructor from file. | |||||
| myDataBuffer(NULL), // No data buffer yet. | myDataBuffer(NULL), // No data buffer yet. | ||||
| myBufferSize(0), // No length yet. | myBufferSize(0), // No length yet. | ||||
| myIndex(0), // Our Index is zero | myIndex(0), // Our Index is zero | ||||
| myLine(1) { // We start on line 1 | myLine(1) { // We start on line 1 | ||||
| try { // Capture any throws. | try { // Capture any throws. | ||||
| ifstream CFGFile(FileName.c_str()); // Open the file. | |||||
| CFGFile.seekg(0,ios::end); // Seek to the end | |||||
| std::ifstream CFGFile(FileName.c_str()); // Open the file. | |||||
| CFGFile.seekg(0,std::ios::end); // Seek to the end | |||||
| myBufferSize = CFGFile.tellg(); // to find out what size it is. | myBufferSize = CFGFile.tellg(); // to find out what size it is. | ||||
| myDataBuffer = newCStringBuffer(myBufferSize); // Make a new buffer the right size. | myDataBuffer = newCStringBuffer(myBufferSize); // Make a new buffer the right size. | ||||
| CFGFile.seekg(0,ios::beg); // Seek to the beginning and | |||||
| CFGFile.seekg(0,std::ios::beg); // Seek to the beginning and | |||||
| CFGFile.read(myDataBuffer, myBufferSize); // read the file into the buffer. | CFGFile.read(myDataBuffer, myBufferSize); // read the file into the buffer. | ||||
| if(CFGFile.bad()) { // If the read failed, we're unusable! | if(CFGFile.bad()) { // If the read failed, we're unusable! | ||||
| delete[] myDataBuffer; // Delete the buffer | delete[] myDataBuffer; // Delete the buffer | ||||
| } // true. | } // true. | ||||
| } | } | ||||
| } // End namespace codedweller |
| // configuration.hpp | // configuration.hpp | ||||
| // | // | ||||
| // (C) 2006 - 2009 MicroNeil Research Corporation. | |||||
| // See http://www.codedweller.com for details. | |||||
| // | |||||
| // This program is free software; you can redistribute it and/or modify it | |||||
| // under the terms of the GNU General Public License as published by the | |||||
| // Free Software Foundation; either version 2 of the License, or (at your | |||||
| // option) any later version. | |||||
| // | |||||
| // This program is distributed in the hope that it will be useful, but WITHOUT | |||||
| // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |||||
| // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |||||
| // more details. | |||||
| // | |||||
| // You should have received a copy of the GNU General Public License along with | |||||
| // this program; if not, write to the Free Software Foundation, Inc., 59 Temple | |||||
| // Place, Suite 330, Boston, MA 02111-1307 USA | |||||
| // Copyright (C) 2004-2020 MicroNeil Research Corporation. | |||||
| // | // | ||||
| // This software is released under the MIT license. See LICENSE.TXT. | |||||
| // What about this ============================================================= | // What about this ============================================================= | ||||
| // The configuration module provides a platform for reading configuration files | // The configuration module provides a platform for reading configuration files | ||||
| // (or string data) containing well-formed xml and mapping that data to program | // (or string data) containing well-formed xml and mapping that data to program | ||||
| // variables. | // variables. | ||||
| // | |||||
| // The idea is to provide the ability for an object or application to provide | // The idea is to provide the ability for an object or application to provide | ||||
| // a modular "configuration" object that models a hierarchical collection of | // a modular "configuration" object that models a hierarchical collection of | ||||
| // "settings" that can be represented easily in code and in xml. | // "settings" that can be represented easily in code and in xml. | ||||
| // Include This Header Once Only =============================================== | // Include This Header Once Only =============================================== | ||||
| #ifndef configuration_included | |||||
| #define configuration_included | |||||
| #pragma once | |||||
| #include <string> | #include <string> | ||||
| #include <vector> | #include <vector> | ||||
| #include <cstdlib> | #include <cstdlib> | ||||
| #include <list> | #include <list> | ||||
| using namespace std; | |||||
| namespace codedweller { | |||||
| class ConfigurationElement; // Elements exist | class ConfigurationElement; // Elements exist | ||||
| class ConfigurationAttribute; // Attributes exist | class ConfigurationAttribute; // Attributes exist | ||||
| private: | private: | ||||
| string myName; // Elements have a name. | |||||
| std::string myName; // Elements have a name. | |||||
| // External important things I remember but don't touch... | // External important things I remember but don't touch... | ||||
| ConfigurationElement* myParent; // They may have a parrent. | ConfigurationElement* myParent; // They may have a parrent. | ||||
| list<Configurator*> myStartConfigurators; // Call these when we start Interpret() | |||||
| list<Configurator*> myEndConfigurators; // Call these when we finish Interpret() | |||||
| 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... | // Internal / subordinate things I own and kill... | ||||
| list<ConfigurationAttribute*> myAttributes; // They may have a list of attributes. | |||||
| list<ConfigurationElement*> myElements; // They may have a list of sub-elements. | |||||
| list<ConfigurationMnemonic*> myMnemonics; // They may have a list of mnemonics. | |||||
| list<ConfigurationTranslator*> myTranslators; // They may have a list of translators. | |||||
| 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... | // During Interpret() operations we keep track of where we are seen... | ||||
| public: | public: | ||||
| ConfigurationElement(const char* Name); // Must be constructed with a name | ConfigurationElement(const char* Name); // Must be constructed with a name | ||||
| ConfigurationElement(const string Name); // either c string or c++ string. | |||||
| 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 char* Name, ConfigurationElement& Parent); // Sub-elements are constructed with a | ||||
| ConfigurationElement(const string Name, ConfigurationElement& Parent); // parrent. | |||||
| ConfigurationElement(const std::string Name, ConfigurationElement& Parent); // parrent. | |||||
| // Upon desctruction an element will delete all subordinate objects: | // Upon desctruction an element will delete all subordinate objects: | ||||
| // * All sub element objects. | // * All sub element objects. | ||||
| // Elements can be probed for some simple, useful things. | // Elements can be probed for some simple, useful things. | ||||
| string Name(); // Get the name of this element. | |||||
| std::string Name(); // Get the name of this element. | |||||
| ConfigurationElement& Parent(); // Get the parent of this element. | ConfigurationElement& Parent(); // Get the parent of this element. | ||||
| ConfigurationElement& Parent(ConfigurationElement& newParent); // Set the parent of this element. | ConfigurationElement& Parent(ConfigurationElement& newParent); // Set the parent of this element. | ||||
| // Elements can contain either data or sub-elements. | // 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 char* Name); // Add a new sub element by c string name. | ||||
| ConfigurationElement& Element(const string 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. | //// Mapping element factory methods for convenience. | ||||
| //// Root-Node elements are _usually_ empty and without attributes in xml | //// Root-Node elements are _usually_ empty and without attributes in xml | ||||
| ConfigurationElement& Element( // Mapping factory for convenience, | ConfigurationElement& Element( // Mapping factory for convenience, | ||||
| const char* Name, // requires a name, of course, | const char* Name, // requires a name, of course, | ||||
| string& x, string init = string("")); // Map to a string. | |||||
| std::string& x, std::string init = std::string("")); // Map to a string. | |||||
| ConfigurationElement& Element( // Mapping factory for convenience, | ConfigurationElement& Element( // Mapping factory for convenience, | ||||
| const char* Name, // requires a name, of course, | const char* Name, // requires a name, of course, | ||||
| // string versions | // string versions | ||||
| ConfigurationElement& Element( // Mapping factory for convenience, | ConfigurationElement& Element( // Mapping factory for convenience, | ||||
| const string Name, // requires a name, of course, | |||||
| const std::string Name, // requires a name, of course, | |||||
| ConfigurationTranslator& newTranslator); // Add a Translator to this element. | ConfigurationTranslator& newTranslator); // Add a Translator to this element. | ||||
| ConfigurationElement& Element( // Mapping factory for convenience, | ConfigurationElement& Element( // Mapping factory for convenience, | ||||
| const string Name, // requires a name, of course, | |||||
| string& x, string init = string("")); // Map to a string. | |||||
| 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, | ConfigurationElement& Element( // Mapping factory for convenience, | ||||
| const string Name, // requires a name, of course, | |||||
| const std::string Name, // requires a name, of course, | |||||
| int& x, int init = 0, int radix = 0); // Map to an int. | int& x, int init = 0, int radix = 0); // Map to an int. | ||||
| ConfigurationElement& Element( // Mapping factory for convenience, | ConfigurationElement& Element( // Mapping factory for convenience, | ||||
| const string Name, // requires a name, of course, | |||||
| const std::string Name, // requires a name, of course, | |||||
| double& x, double init = 0.0); // Map to a double. | double& x, double init = 0.0); // Map to a double. | ||||
| ConfigurationElement& Element( // Mapping factory for convenience, | ConfigurationElement& Element( // Mapping factory for convenience, | ||||
| const string Name, // requires a name, of course, | |||||
| const std::string Name, // requires a name, of course, | |||||
| bool& x, bool init = false); // Map to a boolean. | bool& x, bool init = false); // Map to a boolean. | ||||
| // End methods for heading back up the tree at the end of an element. | // End methods for heading back up the tree at the end of an element. | ||||
| ConfigurationElement& End(); // Return this element's parent. | ConfigurationElement& End(); // Return this element's parent. | ||||
| ConfigurationElement& End(const char* Name); // Check the name and return the parent | ConfigurationElement& End(const char* Name); // Check the name and return the parent | ||||
| ConfigurationElement& End(const string Name); // if the name is correct - or throw! | |||||
| ConfigurationElement& End(const std::string Name); // if the name is correct - or throw! | |||||
| // Elements can have attributes. | // Elements can have attributes. | ||||
| ConfigurationAttribute& Attribute(const char* Name); // Add an attribute using a cstring. | ConfigurationAttribute& Attribute(const char* Name); // Add an attribute using a cstring. | ||||
| ConfigurationAttribute& Attribute(const string Name); // Add an attribute using a c++ string. | |||||
| ConfigurationAttribute& Attribute(const std::string Name); // Add an attribute using a c++ string. | |||||
| //// Mapping Attribute factory methods for convenience. | //// Mapping Attribute factory methods for convenience. | ||||
| ConfigurationAttribute& Attribute( // Mapping factory for convenience, | ConfigurationAttribute& Attribute( // Mapping factory for convenience, | ||||
| const char* Name, // requires a name, of course, | const char* Name, // requires a name, of course, | ||||
| string& x, string init = string("")); // Map to a string. | |||||
| std::string& x, std::string init = std::string("")); // Map to a string. | |||||
| ConfigurationAttribute& Attribute( // Mapping factory for convenience, | ConfigurationAttribute& Attribute( // Mapping factory for convenience, | ||||
| const char* Name, // requires a name, of course, | const char* Name, // requires a name, of course, | ||||
| // string versions | // string versions | ||||
| ConfigurationAttribute& Attribute( // Mapping factory for convenience, | ConfigurationAttribute& Attribute( // Mapping factory for convenience, | ||||
| const string Name, // requires a name, of course, | |||||
| const std::string Name, // requires a name, of course, | |||||
| ConfigurationTranslator& newTranslator); // Add a Translator to this element. | ConfigurationTranslator& newTranslator); // Add a Translator to this element. | ||||
| ConfigurationAttribute& Attribute( // Mapping factory for convenience, | ConfigurationAttribute& Attribute( // Mapping factory for convenience, | ||||
| const string Name, // requires a name, of course, | |||||
| string& x, string init = string("")); // Map to a string. | |||||
| 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, | ConfigurationAttribute& Attribute( // Mapping factory for convenience, | ||||
| const string Name, // requires a name, of course, | |||||
| const std::string Name, // requires a name, of course, | |||||
| int& x, int init = 0, int radix = 0); // Map to an int. | int& x, int init = 0, int radix = 0); // Map to an int. | ||||
| ConfigurationAttribute& Attribute( // Mapping factory for convenience, | ConfigurationAttribute& Attribute( // Mapping factory for convenience, | ||||
| const string Name, // requires a name, of course, | |||||
| const std::string Name, // requires a name, of course, | |||||
| double& x, double init = 0.0); // Map to a double. | double& x, double init = 0.0); // Map to a double. | ||||
| ConfigurationAttribute& Attribute( // Mapping factory for convenience, | ConfigurationAttribute& Attribute( // Mapping factory for convenience, | ||||
| const string Name, // requires a name, of course, | |||||
| const std::string Name, // requires a name, of course, | |||||
| bool& x, bool init = false); // Map to a boolean. | bool& x, bool init = false); // Map to a boolean. | ||||
| // Elements can Initialize() at each Interpret() call. | // Elements can Initialize() at each Interpret() call. | ||||
| // converts it into the expected type, and sets one or more variables | // converts it into the expected type, and sets one or more variables | ||||
| // to the converted value. Usually - just one variable. | // to the converted value. Usually - just one variable. | ||||
| ConfigurationElement& mapTo(ConfigurationTranslator& newTranslator); // Add a Translator to this element. | |||||
| ConfigurationElement& mapTo(string& x, string init = 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. | |||||
| 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 | // An Element's contents may use some special mnemonics to make a | ||||
| // configuration easier to understand and less error prone. When the | // configuration easier to understand and less error prone. When the | ||||
| // contents match a mnemnoic then the translation of the mnemonic is | // contents match a mnemnoic then the translation of the mnemonic is | ||||
| // passed to the Translators instead of the raw contents. | // 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 string value); // Add a mnemonic using c & c++ strings. | |||||
| ConfigurationElement& Mnemonic(const string name, const char* value); // Add a mnemonic using c++ & c strings. | |||||
| ConfigurationElement& Mnemonic(const string name, const string value); // Add a mnemonic using c++ strings. | |||||
| 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 | // The way data gets into an element tree is that it is Interpret()ed | ||||
| // recursively. The data is loaded into a ConfigurationData object which | // recursively. The data is loaded into a ConfigurationData object which | ||||
| private: | private: | ||||
| string myName; // Elements have a name. | |||||
| std::string myName; // Elements have a name. | |||||
| ConfigurationElement& myParent; // They may have a parrent. | ConfigurationElement& myParent; // They may have a parrent. | ||||
| list<ConfigurationMnemonic*> myMnemonics; // They may have a list of mnemonics. | |||||
| list<ConfigurationTranslator*> myTranslators; // They may have a list of translators. | |||||
| 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 myLine; // Last line number I was seen on. | ||||
| int myIndex; // Last char position I was seen on. | int myIndex; // Last char position I was seen on. | ||||
| public: | public: | ||||
| ConfigurationAttribute(const char* Name, ConfigurationElement& Parent); // Sub-elements are constructed with a | |||||
| ConfigurationAttribute(const string Name, ConfigurationElement& Parent); // parrent. | |||||
| 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. | // Attributes delete their Mnemonics and Translators when they go. | ||||
| // See Elements for similar warnings about objects provided to | // See Elements for similar warnings about objects provided to | ||||
| // Attributes can be probed for some simple, useful things. | // Attributes can be probed for some simple, useful things. | ||||
| string Name(); // Get the name of this attribute. | |||||
| std::string Name(); // Get the name of this attribute. | |||||
| ConfigurationElement& Parent(); // Get the parent of this attribute. | ConfigurationElement& Parent(); // Get the parent of this attribute. | ||||
| int Line(); // Get the last line number. | int Line(); // Get the last line number. | ||||
| int Index(); // Get the last data position. | int Index(); // Get the last data position. | ||||
| //// For switching back to the parent element and adding new sub-elements. | //// 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 char* Name); // Add a new sub element by c string name. | ||||
| ConfigurationElement& Element(const string 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. | //// Mapping element factory methods for convenience. | ||||
| //// Root-Node elements are _usually_ empty and without attributes in xml | //// Root-Node elements are _usually_ empty and without attributes in xml | ||||
| ConfigurationElement& Element( // Mapping factory for convenience, | ConfigurationElement& Element( // Mapping factory for convenience, | ||||
| const char* Name, // requires a name, of course, | const char* Name, // requires a name, of course, | ||||
| string& x, string init = string("")); // Map to a string. | |||||
| std::string& x, std::string init = std::string("")); // Map to a string. | |||||
| ConfigurationElement& Element( // Mapping factory for convenience, | ConfigurationElement& Element( // Mapping factory for convenience, | ||||
| const char* Name, // requires a name, of course, | const char* Name, // requires a name, of course, | ||||
| // string versions | // string versions | ||||
| ConfigurationElement& Element( // Mapping factory for convenience, | ConfigurationElement& Element( // Mapping factory for convenience, | ||||
| const string Name, // requires a name, of course, | |||||
| const std::string Name, // requires a name, of course, | |||||
| ConfigurationTranslator& newTranslator); // Add a Translator to this element. | ConfigurationTranslator& newTranslator); // Add a Translator to this element. | ||||
| ConfigurationElement& Element( // Mapping factory for convenience, | ConfigurationElement& Element( // Mapping factory for convenience, | ||||
| const string Name, // requires a name, of course, | |||||
| string& x, string init = string("")); // Map to a string. | |||||
| 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, | ConfigurationElement& Element( // Mapping factory for convenience, | ||||
| const string Name, // requires a name, of course, | |||||
| const std::string Name, // requires a name, of course, | |||||
| int& x, int init = 0, int radix = 0); // Map to an int. | int& x, int init = 0, int radix = 0); // Map to an int. | ||||
| ConfigurationElement& Element( // Mapping factory for convenience, | ConfigurationElement& Element( // Mapping factory for convenience, | ||||
| const string Name, // requires a name, of course, | |||||
| const std::string Name, // requires a name, of course, | |||||
| double& x, double init = 0.0); // Map to a double. | double& x, double init = 0.0); // Map to a double. | ||||
| ConfigurationElement& Element( // Mapping factory for convenience, | ConfigurationElement& Element( // Mapping factory for convenience, | ||||
| const string Name, // requires a name, of course, | |||||
| const std::string Name, // requires a name, of course, | |||||
| bool& x, bool init = false); // Map to a boolean. | bool& x, bool init = false); // Map to a boolean. | ||||
| // End methods for heading back up the tree at the end of an element. | // End methods for heading back up the tree at the end of an element. | ||||
| ConfigurationElement& End(); // Return this element's parent. | ConfigurationElement& End(); // Return this element's parent. | ||||
| ConfigurationElement& End(const char* Name); // Check the name and return the parent | ConfigurationElement& End(const char* Name); // Check the name and return the parent | ||||
| ConfigurationElement& End(const string Name); // if the name is correct - or throw! | |||||
| ConfigurationElement& End(const std::string Name); // if the name is correct - or throw! | |||||
| //// For adding new attributes to the parent element. | //// For adding new attributes to the parent element. | ||||
| ConfigurationAttribute& Attribute(const char* Name); // Add an attribute using a cstring. | ConfigurationAttribute& Attribute(const char* Name); // Add an attribute using a cstring. | ||||
| ConfigurationAttribute& Attribute(const string Name); // Add an attribute using a c++ string. | |||||
| ConfigurationAttribute& Attribute(const std::string Name); // Add an attribute using a c++ string. | |||||
| //// Mapping Attribute factory methods for convenience. | //// Mapping Attribute factory methods for convenience. | ||||
| ConfigurationAttribute& Attribute( // Mapping factory for convenience, | ConfigurationAttribute& Attribute( // Mapping factory for convenience, | ||||
| const char* Name, // requires a name, of course, | const char* Name, // requires a name, of course, | ||||
| string& x, string init = string("")); // Map to a string. | |||||
| std::string& x, std::string init = std::string("")); // Map to a string. | |||||
| ConfigurationAttribute& Attribute( // Mapping factory for convenience, | ConfigurationAttribute& Attribute( // Mapping factory for convenience, | ||||
| const char* Name, // requires a name, of course, | const char* Name, // requires a name, of course, | ||||
| // string versions | // string versions | ||||
| ConfigurationAttribute& Attribute( // Mapping factory for convenience, | ConfigurationAttribute& Attribute( // Mapping factory for convenience, | ||||
| const string Name, // requires a name, of course, | |||||
| const std::string Name, // requires a name, of course, | |||||
| ConfigurationTranslator& newTranslator); // Add a Translator to this element. | ConfigurationTranslator& newTranslator); // Add a Translator to this element. | ||||
| ConfigurationAttribute& Attribute( // Mapping factory for convenience, | ConfigurationAttribute& Attribute( // Mapping factory for convenience, | ||||
| const string Name, // requires a name, of course, | |||||
| string& x, string init = string("")); // Map to a string. | |||||
| 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, | ConfigurationAttribute& Attribute( // Mapping factory for convenience, | ||||
| const string Name, // requires a name, of course, | |||||
| const std::string Name, // requires a name, of course, | |||||
| int& x, int init = 0, int radix = 0); // Map to an int. | int& x, int init = 0, int radix = 0); // Map to an int. | ||||
| ConfigurationAttribute& Attribute( // Mapping factory for convenience, | ConfigurationAttribute& Attribute( // Mapping factory for convenience, | ||||
| const string Name, // requires a name, of course, | |||||
| const std::string Name, // requires a name, of course, | |||||
| double& x, double init = 0.0); // Map to a double. | double& x, double init = 0.0); // Map to a double. | ||||
| ConfigurationAttribute& Attribute( // Mapping factory for convenience, | ConfigurationAttribute& Attribute( // Mapping factory for convenience, | ||||
| const string Name, // requires a name, of course, | |||||
| const std::string Name, // requires a name, of course, | |||||
| bool& x, bool init = false); // Map to a boolean. | bool& x, bool init = false); // Map to a boolean. | ||||
| //// Set Init On Interprete for the parent element. | //// Set Init On Interprete for the parent element. | ||||
| // apply to the parent element's contents. Here they are for use on this | // apply to the parent element's contents. Here they are for use on this | ||||
| // attribute. | // attribute. | ||||
| ConfigurationAttribute& mapTo(ConfigurationTranslator& newTranslator); // Add a Translator to this attribute. | |||||
| ConfigurationAttribute& mapTo(string& x, string init = 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. | |||||
| 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. | // 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 string value); // Add a mnemonic using c & c++ strings. | |||||
| ConfigurationAttribute& Mnemonic(const string name, const char* value); // Add a mnemonic using c++ & c strings. | |||||
| ConfigurationAttribute& Mnemonic(const string name, const string value); // Add a mnemonic using a c++ string. | |||||
| 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. | // Attributes participate in the Interprete() task just like elements. | ||||
| public: | public: | ||||
| ConfigurationData(const char* FileName); // Constructor from c string file name. | ConfigurationData(const char* FileName); // Constructor from c string file name. | ||||
| ConfigurationData(const string 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(const char* Data, int Length); // Raw constructor from text buffer. | ||||
| ~ConfigurationData(); // Destroys the internal buffer etc. | ~ConfigurationData(); // Destroys the internal buffer etc. | ||||
| int Line(); // Reads the current Line number. | int Line(); // Reads the current Line number. | ||||
| int addNewLines(int Count); // Increments the Line number. | int addNewLines(int Count); // Increments the Line number. | ||||
| stringstream Log; // Convenient Interpret log. | |||||
| std::stringstream Log; // Convenient Interpret log. | |||||
| }; | }; | ||||
| // collection of the basic translators used for built-in mapTo()s. | // collection of the basic translators used for built-in mapTo()s. | ||||
| class ConfigurationTranslator { // Translators exist | class ConfigurationTranslator { // Translators exist | ||||
| public: | |||||
| public: | |||||
| virtual ~ConfigurationTranslator(){}; // Stop No Virt Dtor warnings. | virtual ~ConfigurationTranslator(){}; // Stop No Virt Dtor warnings. | ||||
| virtual void translate(const char* Value) = 0; // Pure virtual translator. | virtual void translate(const char* Value) = 0; // Pure virtual translator. | ||||
| virtual void initialize() = 0; // Pure virtual initializer. | virtual void initialize() = 0; // Pure virtual initializer. | ||||
| class StringTranslator : public ConfigurationTranslator { | class StringTranslator : public ConfigurationTranslator { | ||||
| private: | private: | ||||
| string& myVariable; // Variable to map. | |||||
| string myInitializer; // Initial/Default value. | |||||
| std::string& myVariable; // Variable to map. | |||||
| std::string myInitializer; // Initial/Default value. | |||||
| public: | public: | ||||
| StringTranslator( // Construct this with | StringTranslator( // Construct this with | ||||
| string& Variable, // the variable to map, | |||||
| string Inititializer); // and the default value. | |||||
| std::string& Variable, // the variable to map, | |||||
| std::string Inititializer); // and the default value. | |||||
| void translate(const char* Value); // Provide a translation method. | void translate(const char* Value); // Provide a translation method. | ||||
| void initialize(); // Provide an initialization method. | void initialize(); // Provide an initialization method. | ||||
| class ConfigurationMnemonic { // Mnemonics | class ConfigurationMnemonic { // Mnemonics | ||||
| private: | private: | ||||
| string myName; // What is the Mnemonic? | |||||
| string myValue; // What is the translation? | |||||
| std::string myName; // What is the Mnemonic? | |||||
| std::string myValue; // What is the translation? | |||||
| public: | public: | ||||
| ConfigurationMnemonic(string Name, string Value); // To make one, provide both parts. | |||||
| bool test(string Name); // Test to see if this Mnemonic matches. | |||||
| string Value(); // If it does then we will need it's value. | |||||
| 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 ////////////////////////////////////////////////////////////// | //// Configurator ////////////////////////////////////////////////////////////// | ||||
| class Configurator { // Configurators exist | class Configurator { // Configurators exist | ||||
| public: | public: | ||||
| virtual void operator()(ConfigurationElement& E, ConfigurationData& D) = 0; // Pure virtual configurator. | |||||
| virtual void operator()(ConfigurationElement& E, ConfigurationData& D) = 0; // Pure virtual configurator. | |||||
| virtual ~Configurator() {} // Virtual dtor keeps warnings away. | virtual ~Configurator() {} // Virtual dtor keeps warnings away. | ||||
| }; | }; | ||||
| //// Include our inline methods //////////////////////////////////////////////// | |||||
| #include "configuration.inline.hpp" | |||||
| //// Utilities ///////////////////////////////////////////////////////////////// | //// Utilities ///////////////////////////////////////////////////////////////// | ||||
| // SetTrueOnComplete Configurator ////////////////////////////////////////////// | // SetTrueOnComplete Configurator ////////////////////////////////////////////// | ||||
| void operator()(ConfigurationElement& E, ConfigurationData& D); // Handle the operation. | void operator()(ConfigurationElement& E, ConfigurationData& D); // Handle the operation. | ||||
| }; | }; | ||||
| #endif | |||||
| // End Of Include Only Once | |||||
| } // End namespace codedweller |
| // configuration.inline.hpp | |||||
| // | |||||
| // (C) 2006-2009 MicroNeil Research Corporation. | |||||
| // | |||||
| // This program is part of the MicroNeil Research Open Library Project. For | |||||
| // more information go to http://www.microneil.com/OpenLibrary/index.html | |||||
| // | |||||
| // This program is free software; you can redistribute it and/or modify it | |||||
| // under the terms of the GNU General Public License as published by the | |||||
| // Free Software Foundation; either version 2 of the License, or (at your | |||||
| // option) any later version. | |||||
| // | |||||
| // This program is distributed in the hope that it will be useful, but WITHOUT | |||||
| // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |||||
| // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |||||
| // more details. | |||||
| // | |||||
| // You should have received a copy of the GNU General Public License along with | |||||
| // this program; if not, write to the Free Software Foundation, Inc., 59 Temple | |||||
| // Place, Suite 330, Boston, MA 02111-1307 USA | |||||
| // See configuration.hpp for details | |||||
| //// Configuration Element ///////////////////////////////////////////////////// | |||||
| inline ConfigurationElement::ConfigurationElement(const char* Name) : // Construct with a cstring. | |||||
| myName(string(Name)), | |||||
| myParent(NULL), | |||||
| myLine(0), | |||||
| myIndex(0), | |||||
| myLength(0), | |||||
| myCleanFlag(true), | |||||
| myInitOnInterpretFlag(false) { | |||||
| } | |||||
| inline ConfigurationElement::ConfigurationElement(const string Name) : // Construct with a c++ string. | |||||
| myName(Name), | |||||
| myParent(NULL), | |||||
| myLine(0), | |||||
| myIndex(0), | |||||
| myLength(0), | |||||
| myCleanFlag(true), | |||||
| myInitOnInterpretFlag(false) { | |||||
| } | |||||
| inline ConfigurationElement::ConfigurationElement( // Construct sub element w/ cstring. | |||||
| const char* Name, | |||||
| ConfigurationElement& Parent) : | |||||
| myName(string(Name)), | |||||
| myParent(&Parent), | |||||
| myLine(0), | |||||
| myIndex(0), | |||||
| myLength(0), | |||||
| myCleanFlag(true), | |||||
| myInitOnInterpretFlag(false) { | |||||
| } | |||||
| inline ConfigurationElement::ConfigurationElement( // Construct sub element w/ string. | |||||
| const string Name, | |||||
| ConfigurationElement& Parent) : | |||||
| myName(Name), | |||||
| myParent(&Parent), | |||||
| myLine(0), | |||||
| myIndex(0), | |||||
| myLength(0), | |||||
| myCleanFlag(true), | |||||
| myInitOnInterpretFlag(false) { | |||||
| } | |||||
| inline string ConfigurationElement::Name() { return myName; } // Get the name of this element. | |||||
| inline ConfigurationElement& ConfigurationElement::Parent() { // Get the parrent of this element. | |||||
| if(NULL != myParent) { // If I have a parent | |||||
| return (*myParent); // then I dereference and return it. | |||||
| } // If I don't have a parent | |||||
| return (*this); // then I return myself. | |||||
| } | |||||
| inline ConfigurationElement& ConfigurationElement::Parent( // Set the parrent of this element. | |||||
| ConfigurationElement& Parent) { // Given this parent | |||||
| myParent = &Parent; // I take and store it's address | |||||
| return (*myParent); // then dereference and return it. | |||||
| } | |||||
| inline int ConfigurationElement::Line() { return myLine; } // Get the last line number. | |||||
| inline int ConfigurationElement::Index() { return myIndex; } // Get the last data position. | |||||
| inline int ConfigurationElement::Length() { return myLength; } // Get the last length. | |||||
| inline void ConfigurationElement::notifyDirty() { myCleanFlag = false; } // Attributes do this when they change. | |||||
| inline ConfigurationElement& ConfigurationElement::Element(const char* Name) { // Add a new sub element by c string name. | |||||
| return Element(string(Name)); // Use the string name version | |||||
| } | |||||
| inline ConfigurationElement& ConfigurationElement::Element(const string Name) { // Add a new sub element by c++ string name. | |||||
| ConfigurationElement* N = new ConfigurationElement( // Create a new Element with the | |||||
| Name, // name provided and | |||||
| (*this)); // myself as the parent. | |||||
| myElements.push_back(N); // Add it to the list. | |||||
| return (*N); // Return the new element. | |||||
| } | |||||
| inline ConfigurationElement& ConfigurationElement::Element( // Mapping factory for convenience, | |||||
| const char* Name, // requires a name, of course, | |||||
| ConfigurationTranslator& newTranslator) { // Add a Translator to this element. | |||||
| return Element(string(Name), newTranslator); // Use the string name version | |||||
| } | |||||
| inline ConfigurationElement& ConfigurationElement::Element( // Mapping factory for convenience, | |||||
| const char* Name, // requires a name, of course, | |||||
| string& x, string init) { // Map to a string. | |||||
| return Element(string(Name), x, init); // Use the string name version | |||||
| } | |||||
| inline ConfigurationElement& ConfigurationElement::Element( // Mapping factory for convenience, | |||||
| const char* Name, // requires a name, of course, | |||||
| int& x, int init, int radix) { // Map to an int. | |||||
| return Element(string(Name), x, init, radix); // Use the string name version | |||||
| } | |||||
| inline ConfigurationElement& ConfigurationElement::Element( // Mapping factory for convenience, | |||||
| const char* Name, // requires a name, of course, | |||||
| double& x, double init) { // Map to a double. | |||||
| return Element(string(Name), x, init); // Use the string name version | |||||
| } | |||||
| inline ConfigurationElement& ConfigurationElement::Element( // Mapping factory for convenience, | |||||
| const char* Name, // requires a name, of course, | |||||
| bool& x, bool init) { // Map to a boolean. | |||||
| return Element(string(Name), x, init); // Use the string name version | |||||
| } | |||||
| inline ConfigurationElement& ConfigurationElement::End() { // Return this element's parent. | |||||
| return Parent(); // Borrow Parent() | |||||
| } | |||||
| inline ConfigurationElement& ConfigurationElement::End(const char* Name) { // Check the name and return the parent | |||||
| return End(string(Name)); // Borrow End(string) | |||||
| } | |||||
| inline ConfigurationElement& ConfigurationElement::End(const string Name) { // if the name is correct - or throw! | |||||
| if(0 != Name.compare(myName)) { // If Name is not myName | |||||
| throw EndNameDoesNotMatch(); // throw an exception! | |||||
| } // If the names match then | |||||
| return Parent(); // return the parent. | |||||
| } | |||||
| inline ConfigurationAttribute& ConfigurationElement::Attribute( // Add an attribute using a cstring. | |||||
| const char* Name) { // Given this cstring name | |||||
| return Attribute(string(Name)); // Convert it to a string and borrow | |||||
| } // Attribute(string) | |||||
| inline ConfigurationAttribute& ConfigurationElement::Attribute( // Mapping factory for convenience, | |||||
| const char* Name, // requires a name, of course, | |||||
| ConfigurationTranslator& newTranslator) { // Add a Translator to this element. | |||||
| return Attribute(string(Name), newTranslator); // Borrow the string name version | |||||
| } | |||||
| inline ConfigurationAttribute& ConfigurationElement::Attribute( // Mapping factory for convenience, | |||||
| const char* Name, // requires a name, of course, | |||||
| string& x, string init) { // Map to a string. | |||||
| return Attribute(string(Name), x, init); // Borrow the string name version | |||||
| } | |||||
| inline ConfigurationAttribute& ConfigurationElement::Attribute( // Mapping factory for convenience, | |||||
| const char* Name, // requires a name, of course, | |||||
| int& x, int init, int radix) { // Map to an int. | |||||
| return Attribute(string(Name), x, init); // Borrow the string name version | |||||
| } | |||||
| inline ConfigurationAttribute& ConfigurationElement::Attribute( // Mapping factory for convenience, | |||||
| const char* Name, // requires a name, of course, | |||||
| double& x, double init) { // Map to a double. | |||||
| return Attribute(string(Name), x, init); // Borrow the string name version | |||||
| } | |||||
| inline ConfigurationAttribute& ConfigurationElement::Attribute( // Mapping factory for convenience, | |||||
| const char* Name, // requires a name, of course, | |||||
| bool& x, bool init) { // Map to a boolean. | |||||
| return Attribute(string(Name), x, init); // Borrow the string name version | |||||
| } | |||||
| inline ConfigurationElement& ConfigurationElement::setInitOnInterpret() { // Set the init on interpret flag. | |||||
| myInitOnInterpretFlag = true; // Set the flag. | |||||
| return(*this); // Dereference and return self. | |||||
| } | |||||
| inline ConfigurationElement& ConfigurationElement::atStartCall( // Add an atStart call-back. | |||||
| Configurator& Functor) { // Given this Functor, | |||||
| myStartConfigurators.push_back(&Functor); // add it to my atStart list then | |||||
| return(*this); // dereference and return myself. | |||||
| } | |||||
| inline ConfigurationElement& ConfigurationElement::atEndCall( // Add an atEnd call-back. | |||||
| Configurator& Functor) { // Given this Functor, | |||||
| myEndConfigurators.push_back(&Functor); // add it to my atEnd list then | |||||
| return(*this); // dereference and return myself. | |||||
| } | |||||
| inline ConfigurationElement& ConfigurationElement::Mnemonic( // Add a mnemonic using c strings. | |||||
| const char* name, const char* value) { // Given char* and char* | |||||
| return Mnemonic(string(name), string(value)); // make strings and borrow that method. | |||||
| } | |||||
| inline ConfigurationElement& ConfigurationElement::Mnemonic( // Add a mnemonic using mixed strings. | |||||
| const char* name, const string value) { // Given char* and string | |||||
| return Mnemonic(string(name), value); // make strings and borrow that method. | |||||
| } | |||||
| inline ConfigurationElement& ConfigurationElement::Mnemonic( // Add a mnemonic using mixed strings. | |||||
| const string name, const char* value) { // Given string and char* | |||||
| return Mnemonic(name, string(value)); // make strings and borrow that method. | |||||
| } | |||||
| inline ConfigurationElement& ConfigurationElement::Mnemonic( // Add a mnemonic using c++ strings. | |||||
| const string name, const string value) { // Givent string and string | |||||
| ConfigurationMnemonic* N = // Create a new Mnemonic | |||||
| new ConfigurationMnemonic(name, value); // using the values provided, | |||||
| myMnemonics.push_back(N); // add it to my list, then | |||||
| return(*this); // dereference and return myself. | |||||
| } | |||||
| //// Configuration Attribute /////////////////////////////////////////////////// | |||||
| inline ConfigurationAttribute::ConfigurationAttribute( // Attributes are constructed with a | |||||
| const char* Name, ConfigurationElement& Parent) : // Name and a Parent. | |||||
| myName(string(Name)), // We convert the name to a string. | |||||
| myParent(Parent), // We just grab the parent. | |||||
| myLine(0), // Everything else gets zeroed. | |||||
| myIndex(0), | |||||
| myLength(0) { | |||||
| } | |||||
| inline ConfigurationAttribute::ConfigurationAttribute( // Attributes are constrictued with a | |||||
| const string Name, ConfigurationElement& Parent) : // Name and a Parent. | |||||
| myName(Name), // We grab them and zero the rest. | |||||
| myParent(Parent), | |||||
| myLine(0), | |||||
| myIndex(0), | |||||
| myLength(0) { | |||||
| } | |||||
| inline string ConfigurationAttribute::Name() { // Get the name of this attribute. | |||||
| return myName; | |||||
| } | |||||
| inline ConfigurationElement& ConfigurationAttribute::Parent() { // Get the parent of this attribute. | |||||
| return myParent; | |||||
| } | |||||
| inline int ConfigurationAttribute::Line() { // Get the last line number. | |||||
| return myLine; | |||||
| } | |||||
| inline int ConfigurationAttribute::Index() { // Get the last data position. | |||||
| return myIndex; | |||||
| } | |||||
| inline int ConfigurationAttribute::Length() { // Get the last length. | |||||
| return myLength; | |||||
| } | |||||
| inline ConfigurationElement& ConfigurationAttribute::Element( // Add a new sub element by c string name. | |||||
| const char* Name) { | |||||
| return myParent.Element(Name); | |||||
| } | |||||
| inline ConfigurationElement& ConfigurationAttribute::Element( // Add a new sub element by c++ string name. | |||||
| const string Name) { | |||||
| return myParent.Element(Name); | |||||
| } | |||||
| inline ConfigurationElement& ConfigurationAttribute::Element( // Mapping factory for convenience, | |||||
| const char* Name, // requires a name, of course, | |||||
| ConfigurationTranslator& newTranslator) { // Add a Translator to this element. | |||||
| return myParent.Element(Name, newTranslator); | |||||
| } | |||||
| inline ConfigurationElement& ConfigurationAttribute::Element( // Mapping factory for convenience, | |||||
| const char* Name, // requires a name, of course, | |||||
| string& x, string init) { // Map to a string. | |||||
| return myParent.Element(Name, x, init); | |||||
| } | |||||
| inline ConfigurationElement& ConfigurationAttribute::Element( // Mapping factory for convenience, | |||||
| const char* Name, // requires a name, of course, | |||||
| int& x, int init, int radix) { // Map to an int. | |||||
| return myParent.Element(Name, x, init, radix); | |||||
| } | |||||
| inline ConfigurationElement& ConfigurationAttribute::Element( // Mapping factory for convenience, | |||||
| const char* Name, // requires a name, of course, | |||||
| double& x, double init) { // Map to a double. | |||||
| return myParent.Element(Name, x, init); | |||||
| } | |||||
| inline ConfigurationElement& ConfigurationAttribute::Element( // Mapping factory for convenience, | |||||
| const char* Name, // requires a name, of course, | |||||
| bool& x, bool init) { // Map to a boolean. | |||||
| return myParent.Element(Name, x, init); | |||||
| } | |||||
| inline ConfigurationElement& ConfigurationAttribute::Element( // Mapping factory for convenience, | |||||
| const string Name, // requires a name, of course, | |||||
| ConfigurationTranslator& newTranslator) { // Add a Translator to this element. | |||||
| return myParent.Element(Name, newTranslator); | |||||
| } | |||||
| inline ConfigurationElement& ConfigurationAttribute::Element( // Mapping factory for convenience, | |||||
| const string Name, // requires a name, of course, | |||||
| string& x, string init) { // Map to a string. | |||||
| return myParent.Element(Name, x, init); | |||||
| } | |||||
| inline ConfigurationElement& ConfigurationAttribute::Element( // Mapping factory for convenience, | |||||
| const string Name, // requires a name, of course, | |||||
| int& x, int init, int radix) { // Map to an int. | |||||
| return myParent.Element(Name, x, init, radix); | |||||
| } | |||||
| inline ConfigurationElement& ConfigurationAttribute::Element( // Mapping factory for convenience, | |||||
| const string Name, // requires a name, of course, | |||||
| double& x, double init) { // Map to a double. | |||||
| return myParent.Element(Name, x, init); | |||||
| } | |||||
| inline ConfigurationElement& ConfigurationAttribute::Element( // Mapping factory for convenience, | |||||
| const string Name, // requires a name, of course, | |||||
| bool& x, bool init) { // Map to a boolean. | |||||
| return myParent.Element(Name, x, init); | |||||
| } | |||||
| inline ConfigurationElement& ConfigurationAttribute::End() { // Return this element's parent. | |||||
| return myParent.End(); | |||||
| } | |||||
| inline ConfigurationElement& ConfigurationAttribute::End(const char* Name) { // Check the name and return the parent | |||||
| return myParent.End(Name); | |||||
| } | |||||
| inline ConfigurationElement& ConfigurationAttribute::End(const string Name) { // if the name is correct - or throw! | |||||
| return myParent.End(Name); | |||||
| } | |||||
| inline ConfigurationAttribute& ConfigurationAttribute::Attribute( // Add an attribute using a cstring. | |||||
| const char* Name) { | |||||
| return myParent.Attribute(Name); | |||||
| } | |||||
| inline ConfigurationAttribute& ConfigurationAttribute::Attribute( // Add an attribute using a c++ string. | |||||
| const string Name) { | |||||
| return myParent.Attribute(Name); | |||||
| } | |||||
| inline ConfigurationAttribute& ConfigurationAttribute::Attribute( // Mapping factory for convenience, | |||||
| const char* Name, // requires a name, of course, | |||||
| ConfigurationTranslator& newTranslator) { // Add a Translator to this element. | |||||
| return myParent.Attribute(Name, newTranslator); | |||||
| } | |||||
| inline ConfigurationAttribute& ConfigurationAttribute::Attribute( // Mapping factory for convenience, | |||||
| const char* Name, // requires a name, of course, | |||||
| string& x, string init) { // Map to a string. | |||||
| return myParent.Attribute(Name, x, init); | |||||
| } | |||||
| inline ConfigurationAttribute& ConfigurationAttribute::Attribute( // Mapping factory for convenience, | |||||
| const char* Name, // requires a name, of course, | |||||
| int& x, int init, int radix) { // Map to an int. | |||||
| return myParent.Attribute(Name, x, init, radix); | |||||
| } | |||||
| inline ConfigurationAttribute& ConfigurationAttribute::Attribute( // Mapping factory for convenience, | |||||
| const char* Name, // requires a name, of course, | |||||
| double& x, double init) { // Map to a double. | |||||
| return myParent.Attribute(Name, x, init); | |||||
| } | |||||
| inline ConfigurationAttribute& ConfigurationAttribute::Attribute( // Mapping factory for convenience, | |||||
| const char* Name, // requires a name, of course, | |||||
| bool& x, bool init) { // Map to a boolean. | |||||
| return myParent.Attribute(Name, x, init); | |||||
| } | |||||
| inline ConfigurationAttribute& ConfigurationAttribute::Attribute( // Mapping factory for convenience, | |||||
| const string Name, // requires a name, of course, | |||||
| ConfigurationTranslator& newTranslator) { // Add a Translator to this element. | |||||
| return myParent.Attribute(Name, newTranslator); | |||||
| } | |||||
| inline ConfigurationAttribute& ConfigurationAttribute::Attribute( // Mapping factory for convenience, | |||||
| const string Name, // requires a name, of course, | |||||
| string& x, string init) { // Map to a string. | |||||
| return myParent.Attribute(Name, x, init); | |||||
| } | |||||
| inline ConfigurationAttribute& ConfigurationAttribute::Attribute( // Mapping factory for convenience, | |||||
| const string Name, // requires a name, of course, | |||||
| int& x, int init, int radix) { // Map to an int. | |||||
| return myParent.Attribute(Name, x, init, radix); | |||||
| } | |||||
| inline ConfigurationAttribute& ConfigurationAttribute::Attribute( // Mapping factory for convenience, | |||||
| const string Name, // requires a name, of course, | |||||
| double& x, double init) { // Map to a double. | |||||
| return myParent.Attribute(Name, x, init); | |||||
| } | |||||
| inline ConfigurationAttribute& ConfigurationAttribute::Attribute( // Mapping factory for convenience, | |||||
| const string Name, // requires a name, of course, | |||||
| bool& x, bool init) { // Map to a boolean. | |||||
| return myParent.Attribute(Name, x, init); | |||||
| } | |||||
| inline ConfigurationElement& ConfigurationAttribute::setInitOnInterpret() { // Set the init on interpret flag. | |||||
| return myParent.setInitOnInterpret(); | |||||
| } | |||||
| inline ConfigurationElement& ConfigurationAttribute::atStartCall( // Add an atStart call-back to this element. | |||||
| Configurator& Functor) { | |||||
| return myParent.atStartCall(Functor); | |||||
| } | |||||
| inline ConfigurationElement& ConfigurationAttribute::atEndCall( // Add an atEnd call-back to this element. | |||||
| Configurator& Functor) { | |||||
| return myParent.atEndCall(Functor); | |||||
| } | |||||
| inline ConfigurationAttribute& ConfigurationAttribute::Mnemonic( // Add a mnemonic using c strings. | |||||
| const char* name, const char* value) { // Given char* and char* | |||||
| return Mnemonic(string(name), string(value)); // make strings and borrow that method. | |||||
| } | |||||
| inline ConfigurationAttribute& ConfigurationAttribute::Mnemonic( // Add a mnemonic using mixed strings. | |||||
| const char* name, const string value) { // Given char* and string | |||||
| return Mnemonic(string(name), value); // make strings and borrow that method. | |||||
| } | |||||
| inline ConfigurationAttribute& ConfigurationAttribute::Mnemonic( // Add a mnemonic using mixed strings. | |||||
| const string name, const char* value) { // Given string and char* | |||||
| return Mnemonic(name, string(value)); // make strings and borrow that method. | |||||
| } | |||||
| inline ConfigurationAttribute& ConfigurationAttribute::Mnemonic( // Add a mnemonic using c++ strings. | |||||
| const string name, const string value) { // Givent string and string | |||||
| ConfigurationMnemonic* N = // Create a new Mnemonic | |||||
| new ConfigurationMnemonic(name, value); // using the values provided, | |||||
| myMnemonics.push_back(N); // add it to my list, then | |||||
| return(*this); // dereference and return myself. | |||||
| } | |||||
| //// Configuration Data //////////////////////////////////////////////////////// | |||||
| inline char ConfigurationData::Data(int Index) { // Returns char from Data[Index] | |||||
| if(0 > Index || Index >= myBufferSize) { // Check that index is in range | |||||
| return 0; // and return 0 if it is not. | |||||
| } // If Index is within range then | |||||
| return myDataBuffer[Index]; // return the byte requested. | |||||
| } | |||||
| inline int ConfigurationData::Index() { // Reads the current Index. | |||||
| return myIndex; | |||||
| } | |||||
| inline int ConfigurationData::Index(int i) { // Changes the current Index. | |||||
| if(0 > i || i >= myBufferSize) { // If i is out of range then | |||||
| return myIndex; // return the current Index unchanged. | |||||
| } // If i is within range then | |||||
| myIndex = i; // change the Index to i and | |||||
| return myIndex; // return the changed Index. | |||||
| } | |||||
| inline int ConfigurationData::Line() { // Reads the current Line number. | |||||
| return myLine; | |||||
| } | |||||
| inline int ConfigurationData::addNewLines(int Count) { // Increments the Line number. | |||||
| myLine += Count; // Add the number of new lines. | |||||
| return myLine; // Return the current Line number. | |||||
| } | |||||
| //// Configuration Translator ////////////////////////////////////////////////// | |||||
| inline StringTranslator::StringTranslator( // Construct this with | |||||
| string& Variable, // the variable to map, | |||||
| string Initializer) : // and the default value. | |||||
| myVariable(Variable), | |||||
| myInitializer(Initializer) { | |||||
| } | |||||
| inline void StringTranslator::translate(const char* Value) { // Provide a translation method. | |||||
| myVariable = string(Value); // String to String = simple copy. | |||||
| } | |||||
| inline void StringTranslator::initialize() { // Provide an initialization method. | |||||
| myVariable = myInitializer; // Revert to the initializer value. | |||||
| } | |||||
| inline IntegerTranslator::IntegerTranslator( // Construct this with | |||||
| int& Variable, // the variable to map, | |||||
| int Initializer, // and the default value. | |||||
| int Radix) : // For this one we also need a Radix. | |||||
| myVariable(Variable), | |||||
| myInitializer(Initializer), | |||||
| myRadix(Radix) { | |||||
| } | |||||
| inline void IntegerTranslator::translate(const char* Value) { // Provide a translation method. | |||||
| char* dummy; // Throw away ptr for strtol(). | |||||
| myVariable = strtol(Value, &dummy, myRadix); // Convert the string w/ strtol(). | |||||
| } | |||||
| inline void IntegerTranslator::initialize() { // Provide an initialization method. | |||||
| myVariable = myInitializer; // Revert to the initializer value. | |||||
| } | |||||
| inline DoubleTranslator::DoubleTranslator( // Construct this with | |||||
| double& Variable, // the variable to map, | |||||
| double Initializer) : // and the default value. | |||||
| myVariable(Variable), | |||||
| myInitializer(Initializer) { | |||||
| } | |||||
| inline void DoubleTranslator::translate(const char* Value) { // Provide a translation method. | |||||
| char* dummy; // Throw away ptr for strtod(). | |||||
| myVariable = strtod(Value, &dummy); // Convert the string w/ strtod(). | |||||
| } | |||||
| inline void DoubleTranslator::initialize() { // Provide an initialization method. | |||||
| myVariable = myInitializer; // Revert to the initializer value. | |||||
| } | |||||
| inline BoolTranslator::BoolTranslator( // Construct this with | |||||
| bool& Variable, // the variable to map, | |||||
| bool Initializer) : // and the default value. | |||||
| myVariable(Variable), | |||||
| myInitializer(Initializer) { | |||||
| } | |||||
| inline void BoolTranslator::translate(const char* Value) { // Provide a translation method. | |||||
| if( | |||||
| (0 == strcmp(Value,"on")) || | |||||
| (0 == strcmp(Value,"true")) || // on, true, yes, and 1 are | |||||
| (0 == strcmp(Value, "yes")) || // interpreted as a boolean true. | |||||
| (0 == strcmp(Value, "1")) | |||||
| ) { | |||||
| myVariable = true; | |||||
| } else { // Anything else is interpreted as | |||||
| myVariable = false; // boolean false. | |||||
| } | |||||
| } | |||||
| inline void BoolTranslator::initialize() { // Provide an initialization method. | |||||
| myVariable = myInitializer; // Revert to the initializer value. | |||||
| } | |||||
| //// Configuration Mnemonic //////////////////////////////////////////////////// | |||||
| inline ConfigurationMnemonic::ConfigurationMnemonic( // To make one, provide both parts. | |||||
| string Name, string Value) : | |||||
| myName(Name), | |||||
| myValue(Value) { | |||||
| } | |||||
| inline bool ConfigurationMnemonic::test(string Name) { // Test to see if this Mnemonic matches. | |||||
| return (0 == Name.compare(myName)); // Return true if Name and myName match. | |||||
| } | |||||
| inline string ConfigurationMnemonic::Value() { // If it does then we will need it's value. | |||||
| return myValue; | |||||
| } |
| // faults.hpp | // faults.hpp | ||||
| // | // | ||||
| // Copyright (C) MicroNeil Research Corporation 2009 | |||||
| // This file is part of the CodeDweller library. | |||||
| // See www.codedweller.com for details. | |||||
| // Copyright (C) 2004-2020 MicroNeil Research Corporation. | |||||
| // | |||||
| // This software is released under the MIT license. See LICENSE.TXT. | |||||
| // | // | ||||
| // Faults and Checks are classes we can use in place of assert() to handle | // Faults and Checks are classes we can use in place of assert() to handle | ||||
| // unreasonable or necessary conditions in our code. They are constructed with | // unreasonable or necessary conditions in our code. They are constructed with | ||||
| // A Runtime...() throws a runtime_error (self) with it's description in what(). | // A Runtime...() throws a runtime_error (self) with it's description in what(). | ||||
| // A Logic...() throws a logic_error (self) with it's description in what(). | // A Logic...() throws a logic_error (self) with it's description in what(). | ||||
| #ifndef MNR_faults | |||||
| #define MNR_faults | |||||
| #pragma once | |||||
| #include <stdexcept> | #include <stdexcept> | ||||
| #include <cstdlib> | #include <cstdlib> | ||||
| #include <iostream> | #include <iostream> | ||||
| #include <string> | #include <string> | ||||
| using namespace std; | |||||
| namespace codedweller { | |||||
| const int DefaultExitCode = EXIT_FAILURE; // Use this when no code is provided. | const int DefaultExitCode = EXIT_FAILURE; // Use this when no code is provided. | ||||
| private: | private: | ||||
| const string myDescription; // This is what I have to say. | |||||
| const std::string myDescription; // This is what I have to say. | |||||
| public: | public: | ||||
| AbortCheck(const string& Text) : myDescription(Text) {} // I am constructed with a description | |||||
| AbortCheck(const std::string& Text) : myDescription(Text) {} // I am constructed with a description | |||||
| void operator()(bool X) const { // Apply me like assert(exp) | void operator()(bool X) const { // Apply me like assert(exp) | ||||
| if(false == X) { // If the expression is false then we | if(false == X) { // If the expression is false then we | ||||
| cerr << myDescription << endl; // failed the check so we display our | |||||
| std::cerr << myDescription << std::endl; // failed the check so we display our | |||||
| abort(); // description and abort. | abort(); // description and abort. | ||||
| } | } | ||||
| } | } | ||||
| const string Description() { return myDescription; } // You can ask for my Description. | |||||
| const std::string Description() { return myDescription; } // You can ask for my Description. | |||||
| }; | }; | ||||
| class AbortFault { // If this fault occurs we will abort. | class AbortFault { // If this fault occurs we will abort. | ||||
| private: | private: | ||||
| const string myDescription; // This is what I have to say. | |||||
| const std::string myDescription; // This is what I have to say. | |||||
| public: | public: | ||||
| AbortFault(const string& Text) : myDescription(Text) {} // I am constructed with a description | |||||
| AbortFault(const std::string& Text) : myDescription(Text) {} // I am constructed with a description | |||||
| void operator()(bool X) const { // Apply me like assert(! exp) | void operator()(bool X) const { // Apply me like assert(! exp) | ||||
| if(true == X) { // If the expression is true then we | if(true == X) { // If the expression is true then we | ||||
| cerr << myDescription << endl; // have a fault so we display our fault | |||||
| std::cerr << myDescription << std::endl; // have a fault so we display our fault | |||||
| abort(); // description and abort. | abort(); // description and abort. | ||||
| } | } | ||||
| } | } | ||||
| const string Description() const { return myDescription; } // You can ask for my Description. | |||||
| const std::string Description() const { return myDescription; } // You can ask for my Description. | |||||
| }; | }; | ||||
| class ExitCheck { // If this check is false we will exit. | class ExitCheck { // If this check is false we will exit. | ||||
| private: | private: | ||||
| const string myDescription; // This is what I have to say. | |||||
| const std::string myDescription; // This is what I have to say. | |||||
| const int myExitCode; // This is what I send to exit(). | const int myExitCode; // This is what I send to exit(). | ||||
| public: | public: | ||||
| ExitCheck(const string& Text, int Code=DefaultExitCode) : // I am constructed with a description | |||||
| ExitCheck(const std::string& Text, int Code=DefaultExitCode) : // I am constructed with a description | |||||
| myDescription(Text), myExitCode(Code) {} // and (optionlly) an exit code. | myDescription(Text), myExitCode(Code) {} // and (optionlly) an exit code. | ||||
| void operator()(bool X) const { // Apply me like assert(exp) | void operator()(bool X) const { // Apply me like assert(exp) | ||||
| if(false == X) { // If the expression is false then we | if(false == X) { // If the expression is false then we | ||||
| cerr << myDescription << endl; // failed the check so we display our | |||||
| std::cerr << myDescription << std::endl; // failed the check so we display our | |||||
| exit(myExitCode); // description and exit with our code. | exit(myExitCode); // description and exit with our code. | ||||
| } | } | ||||
| } | } | ||||
| const string Description() { return myDescription; } // You can ask for my Description. | |||||
| const std::string Description() { return myDescription; } // You can ask for my Description. | |||||
| const int ExitCode() { return myExitCode; } // You can ask for my ExitCode. | const int ExitCode() { return myExitCode; } // You can ask for my ExitCode. | ||||
| }; | }; | ||||
| private: | private: | ||||
| const string myDescription; // This is what I have to say. | |||||
| const std::string myDescription; // This is what I have to say. | |||||
| const int myExitCode; // This is what I send to exit(). | const int myExitCode; // This is what I send to exit(). | ||||
| public: | public: | ||||
| ExitFault(const string& Text, int Code=DefaultExitCode) : // I am constructed with a description | |||||
| ExitFault(const std::string& Text, int Code=DefaultExitCode) : // I am constructed with a description | |||||
| myDescription(Text), myExitCode(Code) {} // and (optionlly) an exit code. | myDescription(Text), myExitCode(Code) {} // and (optionlly) an exit code. | ||||
| void operator()(bool X) const { // Apply me like assert(! exp) | void operator()(bool X) const { // Apply me like assert(! exp) | ||||
| if(true == X) { // If the expression is true then we | if(true == X) { // If the expression is true then we | ||||
| cerr << myDescription << endl; // have a fault so we display our fault | |||||
| std::cerr << myDescription << std::endl; // have a fault so we display our fault | |||||
| exit(myExitCode); // description and exit with our code. | exit(myExitCode); // description and exit with our code. | ||||
| } | } | ||||
| } | } | ||||
| const string Description() const { return myDescription; } // You can ask for my Description. | |||||
| const std::string Description() const { return myDescription; } // You can ask for my Description. | |||||
| const int ExitCode() const { return myExitCode; } // You can ask for my ExitCode. | const int ExitCode() const { return myExitCode; } // You can ask for my ExitCode. | ||||
| }; | }; | ||||
| class RuntimeCheck : public runtime_error { // Throw if this check fails. | |||||
| class RuntimeCheck : public std::runtime_error { // Throw if this check fails. | |||||
| public: | public: | ||||
| RuntimeCheck(const string& Text) : runtime_error(Text) {} // Construct me with a description. | |||||
| RuntimeCheck(const std::string& Text) : std::runtime_error(Text) {} // Construct me with a description. | |||||
| void operator()(bool X) const { // Apply me like assert(exp) | void operator()(bool X) const { // Apply me like assert(exp) | ||||
| if(false == X) { // If the expression is false then we | if(false == X) { // If the expression is false then we | ||||
| } | } | ||||
| }; | }; | ||||
| class RuntimeFault : public runtime_error { // Throw if we find this fault. | |||||
| class RuntimeFault : public std::runtime_error { // Throw if we find this fault. | |||||
| public: | public: | ||||
| RuntimeFault(const string& Text) : runtime_error(Text) {} // Construct me with a description. | |||||
| RuntimeFault(const std::string& Text) : std::runtime_error(Text) {} // Construct me with a description. | |||||
| void operator()(bool X) const { // Apply me like assert(exp) | void operator()(bool X) const { // Apply me like assert(exp) | ||||
| if(true == X) { // If the expression is true then we | if(true == X) { // If the expression is true then we | ||||
| } | } | ||||
| }; | }; | ||||
| class LogicCheck : public logic_error { // Throw if this check fails. | |||||
| class LogicCheck : public std::logic_error { // Throw if this check fails. | |||||
| public: | public: | ||||
| LogicCheck(const string& Text) : logic_error(Text) {} // Construct me with a description. | |||||
| LogicCheck(const std::string& Text) : std::logic_error(Text) {} // Construct me with a description. | |||||
| void operator()(bool X) const { // Apply me like assert(exp) | void operator()(bool X) const { // Apply me like assert(exp) | ||||
| if(false == X) { // If the expression is false then we | if(false == X) { // If the expression is false then we | ||||
| } | } | ||||
| }; | }; | ||||
| class LogicFault : public logic_error { // Throw if we find this fault. | |||||
| class LogicFault : public std::logic_error { // Throw if we find this fault. | |||||
| public: | public: | ||||
| LogicFault(const string& Text) : logic_error(Text) {} // Construct me with a description. | |||||
| LogicFault(const std::string& Text) : std::logic_error(Text) {} // Construct me with a description. | |||||
| void operator()(bool X) const { // Apply me like assert(exp) | void operator()(bool X) const { // Apply me like assert(exp) | ||||
| if(true == X) { // If the expression is true then we | if(true == X) { // If the expression is true then we | ||||
| } | } | ||||
| }; | }; | ||||
| #endif | |||||
| // End Of Include MNR_faults Once Only ========================================= | |||||
| } // End namespace codedweller |
| // histogram.hpp | // histogram.hpp | ||||
| // Copyright (C) 2006 - 2009 MicroNeil Research Corporation | |||||
| // Class to capture a histogram of events using a <set> | |||||
| // | |||||
| // Copyright (C) 2004-2020 MicroNeil Research Corporation. | |||||
| // | |||||
| // This software is released under the MIT license. See LICENSE.TXT. | |||||
| #ifndef mn_histogram_included | |||||
| #define mn_histogram_included | |||||
| #pragma once | |||||
| #include <set> | #include <set> | ||||
| using namespace std; | |||||
| namespace codedweller { | |||||
| /** The Histogram class is managed set of HistogramRecords. | /** The Histogram class is managed set of HistogramRecords. | ||||
| *** We play some naughty tricks with pointers to break the rules and | *** We play some naughty tricks with pointers to break the rules and | ||||
| class HistogramRecord { // A record to assocate a key and count. | class HistogramRecord { // A record to assocate a key and count. | ||||
| public: | public: | ||||
| int Key; // Here is the key. | int Key; // Here is the key. | ||||
| int Count; // Here is the count. | |||||
| mutable int Count; // Here is the count. | |||||
| HistogramRecord(const int NewKey) : // We must have a key to make one. | HistogramRecord(const int NewKey) : // We must have a key to make one. | ||||
| Key(NewKey), Count(0) {} // and a new one starts at count 0. | Key(NewKey), Count(0) {} // and a new one starts at count 0. | ||||
| } | } | ||||
| }; | }; | ||||
| class Histogram : public set<HistogramRecord> { // A Histogram is a set of HistogramRecords | |||||
| class Histogram : public std::set<HistogramRecord> { // A Histogram is a set of HistogramRecords | |||||
| private: // and a private hit counter... | private: // and a private hit counter... | ||||
| int HitCount; | int HitCount; | ||||
| public: | public: | ||||
| int hit(const int EventKey, const int Adjustment = 1) { // hit() method increments a specific count. | int hit(const int EventKey, const int Adjustment = 1) { // hit() method increments a specific count. | ||||
| HistogramRecord E(EventKey); // First, make a record for the event key. | HistogramRecord E(EventKey); // First, make a record for the event key. | ||||
| insert(E); // Insert the new record (if it's not there). | insert(E); // Insert the new record (if it's not there). | ||||
| set<HistogramRecord>::iterator iE = // Find either the pre-existing or the new | |||||
| std::set<HistogramRecord>::iterator iE = // Find either the pre-existing or the new | |||||
| find(E); // record for this key. | find(E); // record for this key. | ||||
| int* C; // Play naughty pointer games to access | int* C; // Play naughty pointer games to access | ||||
| C = const_cast<int*>(&((*iE).Count)); // the Count for this record inside the | C = const_cast<int*>(&((*iE).Count)); // the Count for this record inside the | ||||
| } | } | ||||
| }; | }; | ||||
| #endif | |||||
| } // End namespace codedweller | |||||
| // MANGLER.CPP | // MANGLER.CPP | ||||
| // | // | ||||
| // (C) 1984-2009 MicroNeil Research Corporation | |||||
| // Copyright (C) 2004-2020 MicroNeil Research Corporation. | |||||
| // | |||||
| // This software is released under the MIT license. See LICENSE.TXT. | |||||
| // | |||||
| // Derived from Version 1 of Mangler Encryption Algorythm, 1984. | // Derived from Version 1 of Mangler Encryption Algorythm, 1984. | ||||
| // Derived from Version 2 of Mangler Encryption Algorythm, 1998. | // Derived from Version 2 of Mangler Encryption Algorythm, 1998. | ||||
| // | // | ||||
| // 20021008 _M | |||||
| // Found and corrected range bug in ChaosDriver(void) where | |||||
| // ~Position might access a location outside the fill. Replaced | |||||
| // ~Position with Position^0xff which has the intended effect. | |||||
| // 20020119 _M Version 3.0 | |||||
| // | |||||
| // Mangler encryption engine object. | // Mangler encryption engine object. | ||||
| // Using new optimized chaos driver for uniformity experiments. | // Using new optimized chaos driver for uniformity experiments. | ||||
| // Important in this experiment is proof of highest possible entropy. | // Important in this experiment is proof of highest possible entropy. | ||||
| #include "mangler.hpp" | #include "mangler.hpp" | ||||
| unsigned char MANGLER::ChaosDriver(void) { // Return the current | |||||
| namespace codedweller { | |||||
| unsigned char Mangler::ChaosDriver(void) { // Return the current | |||||
| return Fill[Fill[Position]^Fill[Position^0xff]]; // chaos engine output | return Fill[Fill[Position]^Fill[Position^0xff]]; // chaos engine output | ||||
| } // value. | } // value. | ||||
| // value of Position and determining the final output value and the Position | // value of Position and determining the final output value and the Position | ||||
| // value itself is used to add complexity to the output. | // value itself is used to add complexity to the output. | ||||
| unsigned char MANGLER::Rotate(unsigned char i) { // Bitwise rotates i | |||||
| unsigned char Mangler::Rotate(unsigned char i) { // Bitwise rotates i | |||||
| return ( | return ( | ||||
| (i & 0x80)? // This operation is | (i & 0x80)? // This operation is | ||||
| (i<<1)+1: // described without | (i<<1)+1: // described without | ||||
| ); | ); | ||||
| } | } | ||||
| void MANGLER::ChaosDriver(unsigned char i) { // Drives chaos engine. | |||||
| void Mangler::ChaosDriver(unsigned char i) { // Drives chaos engine. | |||||
| // First we move our mixing position in the fill buffer forward. | // First we move our mixing position in the fill buffer forward. | ||||
| // same state with the same fill data characteristics or else the two | // same state with the same fill data characteristics or else the two | ||||
| // chaotic systems evolve to further divergent states. | // chaotic systems evolve to further divergent states. | ||||
| unsigned char MANGLER::Encrypt(unsigned char i) { | |||||
| unsigned char Mangler::Encrypt(unsigned char i) { | |||||
| unsigned char g = ChaosDriver() ^ i; // Take the output of the | unsigned char g = ChaosDriver() ^ i; // Take the output of the | ||||
| ChaosDriver(g); // chaos engine and use it | ChaosDriver(g); // chaos engine and use it | ||||
| return g; // to moduleate the input. | return g; // to moduleate the input. | ||||
| } // Then drive the engine | } // Then drive the engine | ||||
| // with the encrypted data. | // with the encrypted data. | ||||
| unsigned char MANGLER::Decrypt(unsigned char i) { | |||||
| unsigned char Mangler::Decrypt(unsigned char i) { | |||||
| unsigned char g = ChaosDriver() ^ i; // Take the output of the | unsigned char g = ChaosDriver() ^ i; // Take the output of the | ||||
| ChaosDriver(i); // chaos engine and use it | ChaosDriver(i); // chaos engine and use it | ||||
| return g; // to demodulate the input. | return g; // to demodulate the input. | ||||
| } // then drive the engine | } // then drive the engine | ||||
| // with the original input. | // with the original input. | ||||
| MANGLER::MANGLER(void) : Position(0) { // The default constructor sets | |||||
| Mangler::Mangler(void) : Position(0) { // The default constructor sets | |||||
| for(unsigned int c = 0;c<256;c++) // the key to the root primary | for(unsigned int c = 0;c<256;c++) // the key to the root primary | ||||
| Fill[c]=(unsigned char) c; // value and Position to 0. | Fill[c]=(unsigned char) c; // value and Position to 0. | ||||
| } | } | ||||
| } // End namespace codedweller |
| // MANGLER.HPP | // MANGLER.HPP | ||||
| // | // | ||||
| // (C) 1984-2009 MicroNeil Research Corporation | |||||
| // Copyright (C) 2004-2020 MicroNeil Research Corporation. | |||||
| // | |||||
| // This software is released under the MIT license. See LICENSE.TXT. | |||||
| // | |||||
| // Derived from Version 1 of Mangler Encryption Algorythm, 1984. | // Derived from Version 1 of Mangler Encryption Algorythm, 1984. | ||||
| // Derived from Version 2 of Mangler Encryption Algorythm, 1998. | // Derived from Version 2 of Mangler Encryption Algorythm, 1998. | ||||
| // | // | ||||
| // 20020119 _M Mangler V3. | // 20020119 _M Mangler V3. | ||||
| // Mangler object header file. | // Mangler object header file. | ||||
| // If it's already been included, it doesn't need to be included again. | |||||
| #ifndef _MANGLER_ | |||||
| #define _MANGLER_ | |||||
| #pragma once | |||||
| class MANGLER { | |||||
| namespace codedweller { | |||||
| class Mangler { | |||||
| private: | private: | ||||
| unsigned char Fill[256]; // Where to store the fill. | unsigned char Fill[256]; // Where to store the fill. | ||||
| unsigned char Encrypt(unsigned char i); // Returns encrypted data. | unsigned char Encrypt(unsigned char i); // Returns encrypted data. | ||||
| unsigned char Decrypt(unsigned char i); // Returns decrypted data. | unsigned char Decrypt(unsigned char i); // Returns decrypted data. | ||||
| MANGLER(void); // Default. | |||||
| Mangler(void); // Default. | |||||
| }; | }; | ||||
| #endif | |||||
| } // End namespace codedweller |
| // mishmash.cpp (c) 20190407 _M | |||||
| // non-cryptographic has for short strings | |||||
| // mishmash.cpp | |||||
| // | |||||
| // Copyright (C) 2019-2020 MicroNeil Research Corporation. | |||||
| // | |||||
| // This software is released under the MIT license. See LICENSE.TXT. | |||||
| // | |||||
| // Mishmash is a non-cryptographic hash optimized for short strings. | |||||
| #include "mishmash.hpp" | #include "mishmash.hpp" | ||||
| namespace codedweller { | namespace codedweller { | ||||
| uint32_t primes[256] { | |||||
| 1019, 1021, 1031, 1033, 1039, 1049, 1051, 1061, | |||||
| 1063, 1069, 1087, 1091, 1093, 1097, 1103, 1109, | |||||
| 1117, 1123, 1129, 1151, 1153, 1163, 1171, 1181, | |||||
| 1187, 1193, 1201, 1213, 1217, 1223, 1229, 1231, | |||||
| 1237, 1249, 1259, 1277, 1279, 1283, 1289, 1291, | |||||
| 1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361, | |||||
| 1367, 1373, 1381, 1399, 1409, 1423, 1427, 1429, | |||||
| 1433, 1439, 1447, 1451, 1453, 1459, 1471, 1481, | |||||
| uint32_t primes[256] { | |||||
| 1019, 1021, 1031, 1033, 1039, 1049, 1051, 1061, | |||||
| 1063, 1069, 1087, 1091, 1093, 1097, 1103, 1109, | |||||
| 1117, 1123, 1129, 1151, 1153, 1163, 1171, 1181, | |||||
| 1187, 1193, 1201, 1213, 1217, 1223, 1229, 1231, | |||||
| 1237, 1249, 1259, 1277, 1279, 1283, 1289, 1291, | |||||
| 1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361, | |||||
| 1367, 1373, 1381, 1399, 1409, 1423, 1427, 1429, | |||||
| 1433, 1439, 1447, 1451, 1453, 1459, 1471, 1481, | |||||
| 1483, 1487, 1489, 1493, 1499, 1511, 1523, 1531, | |||||
| 1543, 1549, 1553, 1559, 1567, 1571, 1579, 1583, | |||||
| 1597, 1601, 1607, 1609, 1613, 1619, 1621, 1627, | |||||
| 1637, 1657, 1663, 1667, 1669, 1693, 1697, 1699, | |||||
| 1709, 1721, 1723, 1733, 1741, 1747, 1753, 1759, | |||||
| 1777, 1783, 1787, 1789, 1801, 1811, 1823, 1831, | |||||
| 1847, 1861, 1867, 1871, 1873, 1877, 1879, 1889, | |||||
| 1901, 1907, 1913, 1931, 1933, 1949, 1951, 1973, | |||||
| 1483, 1487, 1489, 1493, 1499, 1511, 1523, 1531, | |||||
| 1543, 1549, 1553, 1559, 1567, 1571, 1579, 1583, | |||||
| 1597, 1601, 1607, 1609, 1613, 1619, 1621, 1627, | |||||
| 1637, 1657, 1663, 1667, 1669, 1693, 1697, 1699, | |||||
| 1709, 1721, 1723, 1733, 1741, 1747, 1753, 1759, | |||||
| 1777, 1783, 1787, 1789, 1801, 1811, 1823, 1831, | |||||
| 1847, 1861, 1867, 1871, 1873, 1877, 1879, 1889, | |||||
| 1901, 1907, 1913, 1931, 1933, 1949, 1951, 1973, | |||||
| 1979, 1987, 1993, 1997, 1999, 2003, 2011, 2017, | |||||
| 2027, 2029, 2039, 2053, 2063, 2069, 2081, 2083, | |||||
| 2087, 2089, 2099, 2111, 2113, 2129, 2131, 2137, | |||||
| 2141, 2143, 2153, 2161, 2179, 2203, 2207, 2213, | |||||
| 2221, 2237, 2239, 2243, 2251, 2267, 2269, 2273, | |||||
| 2281, 2287, 2293, 2297, 2309, 2311, 2333, 2339, | |||||
| 2341, 2347, 2351, 2357, 2371, 2377, 2381, 2383, | |||||
| 2389, 2393, 2399, 2411, 2417, 2423, 2437, 2441, | |||||
| 2447, 2459, 2467, 2473, 2477, 2503, 2521, 2531, | |||||
| 2539, 2543, 2549, 2551, 2557, 2579, 2591, 2593, | |||||
| 2609, 2617, 2621, 2633, 2647, 2657, 2659, 2663, | |||||
| 2671, 2677, 2683, 2687, 2689, 2693, 2699, 2707, | |||||
| 2711, 2713, 2719, 2729, 2731, 2741, 2749, 2753, | |||||
| 2767, 2777, 2789, 2791, 2797, 2801, 2803, 2819, | |||||
| 2833, 2837, 2843, 2851, 2857, 2861, 2879, 2887, | |||||
| 2897, 2903, 2909, 2917, 2927, 2939, 2953, 2957 | |||||
| }; | |||||
| 1979, 1987, 1993, 1997, 1999, 2003, 2011, 2017, | |||||
| 2027, 2029, 2039, 2053, 2063, 2069, 2081, 2083, | |||||
| 2087, 2089, 2099, 2111, 2113, 2129, 2131, 2137, | |||||
| 2141, 2143, 2153, 2161, 2179, 2203, 2207, 2213, | |||||
| 2221, 2237, 2239, 2243, 2251, 2267, 2269, 2273, | |||||
| 2281, 2287, 2293, 2297, 2309, 2311, 2333, 2339, | |||||
| 2341, 2347, 2351, 2357, 2371, 2377, 2381, 2383, | |||||
| 2389, 2393, 2399, 2411, 2417, 2423, 2437, 2441, | |||||
| 2447, 2459, 2467, 2473, 2477, 2503, 2521, 2531, | |||||
| 2539, 2543, 2549, 2551, 2557, 2579, 2591, 2593, | |||||
| 2609, 2617, 2621, 2633, 2647, 2657, 2659, 2663, | |||||
| 2671, 2677, 2683, 2687, 2689, 2693, 2699, 2707, | |||||
| 2711, 2713, 2719, 2729, 2731, 2741, 2749, 2753, | |||||
| 2767, 2777, 2789, 2791, 2797, 2801, 2803, 2819, | |||||
| 2833, 2837, 2843, 2851, 2857, 2861, 2879, 2887, | |||||
| 2897, 2903, 2909, 2917, 2927, 2939, 2953, 2957 | |||||
| }; | |||||
| inline size_t mod256(size_t n) noexcept { return (n & 0xff); } | |||||
| inline uint32_t selectedPrime(size_t n) noexcept { return primes[mod256(n)]; } | |||||
| inline size_t mod256(size_t n) noexcept { return (n & 0xff); } | |||||
| uint32_t mishmash(const unsigned char* buffer, size_t length) noexcept { | |||||
| uint64_t accumulator = selectedPrime(length); | |||||
| for(size_t index = 0; index < length; index++) { | |||||
| unsigned char byte = buffer[index]; | |||||
| accumulator += selectedPrime(index + accumulator); | |||||
| accumulator *= selectedPrime(byte + accumulator); | |||||
| accumulator += accumulator >> 32; | |||||
| accumulator &= 0x00000fffffffffff; | |||||
| } | |||||
| return static_cast<uint32_t>(accumulator); | |||||
| uint32_t mishmash(const unsigned char* buffer, size_t length) noexcept { | |||||
| uint64_t accumulator = selectedPrime(length); | |||||
| for(size_t index = 0; index < length; index++) { | |||||
| unsigned char byte = buffer[index]; | |||||
| accumulator += selectedPrime(index + accumulator); | |||||
| accumulator *= selectedPrime(byte + accumulator); | |||||
| accumulator += accumulator >> 32; | |||||
| accumulator &= 0x00000fffffffffff; | |||||
| } | } | ||||
| return static_cast<uint32_t>(accumulator); | |||||
| } | |||||
| uint32_t mishmash(const std::string& s) noexcept { | |||||
| return mishmash((const unsigned char*) s.c_str(), s.length()); | |||||
| } | |||||
| uint32_t mishmash(const std::string& s) noexcept { | |||||
| return mishmash((const unsigned char*) s.c_str(), s.length()); | |||||
| } | |||||
| uint32_t mishmash(const std::vector<unsigned char>& v) noexcept { | |||||
| return mishmash(v.data(), v.size()); | |||||
| } | |||||
| uint32_t mishmash(const std::vector<unsigned char>& v) noexcept { | |||||
| return mishmash(v.data(), v.size()); | |||||
| } | |||||
| } | } |
| // mishmash.hpp (c) 20190407 _M | |||||
| // mishmash.hpp// | |||||
| // Copyright (C) 2019-2020 MicroNeil Research Corporation. | |||||
| // | // | ||||
| // This software is released under the MIT license. See LICENSE.TXT. | |||||
| // | |||||
| // Mishamash is a non-cryptographic hash optimized for short strings. | |||||
| #pragma once | #pragma once | ||||
| #include <string> | #include <string> | ||||
| namespace codedweller { | namespace codedweller { | ||||
| uint32_t mishmash(const unsigned char* buffer, size_t length) noexcept; | |||||
| uint32_t mishmash(const std::string &s) noexcept; | |||||
| uint32_t mishmash(const std::vector<unsigned char>& v) noexcept; | |||||
| uint32_t mishmash(const unsigned char* buffer, size_t length) noexcept; | |||||
| uint32_t mishmash(const std::string &s) noexcept; | |||||
| uint32_t mishmash(const std::vector<unsigned char>& v) noexcept; | |||||
| } | |||||
| } // End namespace codedweller |
| // networking.cpp | // networking.cpp | ||||
| // Copyright (C) 2006-2009 MicroNeil Research Corporation. | |||||
| // | // | ||||
| // This program is part of the MicroNeil Research Open Library Project. For | |||||
| // more information go to http://www.microneil.com/OpenLibrary/index.html | |||||
| // Copyright (C) 2004-2020 MicroNeil Research Corporation. | |||||
| // | // | ||||
| // This program is free software; you can redistribute it and/or modify it | |||||
| // under the terms of the GNU General Public License as published by the | |||||
| // Free Software Foundation; either version 2 of the License, or (at your | |||||
| // option) any later version. | |||||
| // | |||||
| // This program is distributed in the hope that it will be useful, but WITHOUT | |||||
| // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |||||
| // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |||||
| // more details. | |||||
| // | |||||
| // You should have received a copy of the GNU General Public License along with | |||||
| // this program; if not, write to the Free Software Foundation, Inc., 59 Temple | |||||
| // Place, Suite 330, Boston, MA 02111-1307 USA | |||||
| //============================================================================== | |||||
| // See networking.hpp for notes. | |||||
| // See networking.inline.hpp for inlined methods & functions. | |||||
| // This software is released under the MIT license. See LICENSE.TXT. | |||||
| #include "networking.hpp" | #include "networking.hpp" | ||||
| Networking Network; // Finally creating the Network instance. | |||||
| namespace codedweller { | |||||
| Networking Network; // Creating _THE_ Network instance. | |||||
| #if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64) | |||||
| int Networking::getLastError() { // In windows you get the last error | |||||
| return WSAGetLastError(); // from WSAGetLastError(); | |||||
| } | |||||
| int Networking::setNonBlocking(hSocket socket) { // Set a winsock to non-blocking | |||||
| unsigned long nonblocking = 1; // Create a flag... | |||||
| int result = 0; | |||||
| if(0 != ioctlsocket(socket, FIONBIO, &nonblocking)) { // Set the state of the socket. | |||||
| result = -1; // If that fails then return -1. | |||||
| } | |||||
| return result; // Show 'em my motto! | |||||
| } | |||||
| int Networking::closeSocket(hSocket socket) { // Close a socket in winsock | |||||
| return closesocket(socket); // wraps closesocket(). | |||||
| } | |||||
| bool Networking::WouldBlock(int ErrorCode) { // ErrorCode matches [WSA]EWOULDBLOCK. | |||||
| return (WSAEWOULDBLOCK == ErrorCode); | |||||
| } | |||||
| bool Networking::InProgress(int ErrorCode) { // ErrorCode matches [WSA]EINPROGRESS. | |||||
| return( // [WSA]EALREADY also returns true. | |||||
| WSAEINPROGRESS == ErrorCode || // In fact, on Win* platforms we could | |||||
| WSAEALREADY == ErrorCode || // get any of these when retesting | |||||
| WSAEWOULDBLOCK == ErrorCode || // open() for a connection. | |||||
| WSAEINVAL == ErrorCode | |||||
| ); | |||||
| } | |||||
| bool Networking::IsConnected(int ErrorCode) { // ErrorCode matches [WSA]EISCONN. | |||||
| return(WSAEISCONN == ErrorCode); | |||||
| } | |||||
| #else | |||||
| //// GNU platform | |||||
| int Networking::getLastError() { // In GNU you get the last error | |||||
| return errno; // from errno; | |||||
| } | |||||
| int Networking::setNonBlocking(hSocket socket) { // Set a socket to non-blocking | |||||
| int flags, result; // Grab a place to hold the flags. | |||||
| flags = fcntl(socket, F_GETFL, 0); // Get the current flags. | |||||
| result = fcntl(socket, F_SETFL, flags | O_NONBLOCK); // Set the NONBLOCK flag & return. | |||||
| return result; // Return the result. | |||||
| } | |||||
| int Networking::closeSocket(hSocket socket) { // Close a socket in GNU | |||||
| return close(socket); // wraps close(). | |||||
| } | |||||
| bool Networking::WouldBlock(int ErrorCode) { // ErrorCode matches [WSA]EWOULDBLOCK. | |||||
| return (EWOULDBLOCK == ErrorCode); | |||||
| } | |||||
| bool Networking::InProgress(int ErrorCode) { // ErrorCode matches [WSA]EINPROGRESS. | |||||
| return( // [WSA]EALREADY also returns true. | |||||
| EINPROGRESS == ErrorCode || | |||||
| EALREADY == ErrorCode | |||||
| ); | |||||
| } | |||||
| bool Networking::IsConnected(int ErrorCode) { // ErrorCode matches [WSA]EISCONN. | |||||
| return(EISCONN == ErrorCode); | |||||
| } | |||||
| #endif | |||||
| // End Platform Specific | |||||
| //////////////////////////////////////////////////////////////////////////////// | |||||
| // Begin Platform Agnostic | |||||
| //// class IP4Address ////////////////////////////////////////////////////////// | |||||
| IP4Address::IP4Address():IP(0){} // Blank constructor IP = 0.0.0.0 | |||||
| IP4Address::IP4Address(const unsigned long int newIP):IP(newIP){} // Constructor given unsigned long | |||||
| IP4Address::IP4Address(const IP4Address& newIP):IP(newIP.IP){} // Constructor given an IP4Address | |||||
| IP4Address::IP4Address(const char* newIP) { (*this) = newIP; } // Construcing with a cstring. | |||||
| IP4Address::IP4Address(const std::string& newIP) { (*this) = newIP; } // Constructing with a cppstring. | |||||
| IP4Address& IP4Address::operator=(const unsigned long int Right) { // Convert from unsigned long int. | |||||
| IP = Right; | |||||
| return *this; | |||||
| } | |||||
| IP4Address& IP4Address::operator=(const char* Right) { // Convert from c string. | |||||
| IP = ntohl(inet_addr(Right)); | |||||
| return *this; | |||||
| } | |||||
| IP4Address& IP4Address::operator=(const std::string& Right) { // Convert from cpp string. | |||||
| IP = ntohl(inet_addr(Right.c_str())); | |||||
| return *this; | |||||
| } | |||||
| bool IP4Address::operator<(const IP4Address Right) const { // < Comparison. | |||||
| return (IP < Right.IP); | |||||
| } | |||||
| bool IP4Address::operator>(const IP4Address Right) const { // > Comparison. | |||||
| return (IP > Right.IP); | |||||
| } | |||||
| bool IP4Address::operator==(const IP4Address Right) const { // == Comparison. | |||||
| return (IP == Right.IP); | |||||
| } | |||||
| bool IP4Address::operator!=(const IP4Address Right) const { // != Comparison. | |||||
| return (IP != Right.IP); | |||||
| } | |||||
| bool IP4Address::operator<=(const IP4Address Right) const { // <= Comparison. | |||||
| return (IP <= Right.IP); | |||||
| } | |||||
| bool IP4Address::operator>=(const IP4Address Right) const { // >= Comparison. | |||||
| return (IP >= Right.IP); | |||||
| } | |||||
| //// class SocketAddress /////////////////////////////////////////////////////// | |||||
| void SocketAddress::clear() { | |||||
| memset(&Address, 0, sizeof(Address)); // Zero out the address strcuture | |||||
| Address.sin_family = AF_INET; // Internet Address Family ip4 | |||||
| Address.sin_addr.s_addr = htonl(INADDR_ANY); // Any IP address | |||||
| Address.sin_port = 0; // Zero means any port. | |||||
| } | |||||
| SocketAddress::SocketAddress() { // Constructor sets up w/ wildcards | |||||
| clear(); // Conveniently, we can use clear() :-) | |||||
| } | |||||
| struct sockaddr_in* SocketAddress::getPtr_sockaddr_in() { // Returns a pointer to sockaddr_in. | |||||
| return &Address; // Simply return it's address. | |||||
| } | |||||
| struct sockaddr* SocketAddress::getPtr_sockaddr() { // Returns a pointer to sockaddr. | |||||
| return (struct sockaddr*) &Address; | |||||
| } | |||||
| socklen_t SocketAddress::getAddressSize() { | |||||
| return sizeof(Address); // Return the size of the structure. | |||||
| } | |||||
| void SocketAddress::setAddress(unsigned long ipAddress) { // Set the IP address from an unsigned int | |||||
| Address.sin_addr.s_addr = htonl(ipAddress); // Convert to network order and assign. | |||||
| } | |||||
| void SocketAddress::setAddress(char* ipString) { // Set the IP address from a cstring | |||||
| Address.sin_addr.s_addr = inet_addr(ipString); // Convert to number and assign. | |||||
| } | |||||
| unsigned long SocketAddress::getAddress() { // Get the IP address as an unsigned int | |||||
| return ntohl(Address.sin_addr.s_addr); // Convert to host order and return. | |||||
| } | |||||
| void SocketAddress::setPort(unsigned short port) { // Set the port address from an int | |||||
| Address.sin_port = htons(port); // Convert to network order and set. | |||||
| } | |||||
| void SocketAddress::setPort(char* port) { // Set the port address from a cstring | |||||
| setPort(atoi(port)); // Convert to int and set. | |||||
| } | |||||
| unsigned short SocketAddress::getPort() { // Get the port address as an unsigned int | |||||
| return ntohs(Address.sin_port); // Convert to host order and return. | |||||
| } | |||||
| const char* SocketAddress::getPort(char* str) { // Get the port address into a cstring. | |||||
| if(NULL == str) { // If the caller did not provide a | |||||
| str = PortStringBuffer; // buffer to use then we will use ours. | |||||
| } | |||||
| sprintf(str,"%d",getPort()); // Get the port and convert to cstring. | |||||
| return str; // Return the string we got. | |||||
| } | |||||
| //// class Socket ////////////////////////////////////////////////////////////// | |||||
| Socket::Socket() : // When starting up we are | |||||
| Handle(INVALID_SOCKET), OpenSucceeded(false) { // not yet valid. | |||||
| } | |||||
| Socket::~Socket() { // When shutting down, be sure | |||||
| if(INVALID_SOCKET != Handle) { // any open socket is closed without | |||||
| Network.closeSocket(Handle); // throwing any exceptions. | |||||
| } | |||||
| } | |||||
| void Socket::close() { // When we close, | |||||
| if(INVALID_SOCKET != Handle) { // If the handle is open then | |||||
| if(Network.closeSocket(Handle)) { // close the handle and check for error. | |||||
| LastError = Network.getLastError(); // If there was an error record it. | |||||
| if(!Network.WouldBlock(LastError)) { // If the error was not WOULDBLOCK | |||||
| throw Networking::ControlError( // then throw a ControlError exception. | |||||
| Network.DescriptiveError( | |||||
| "Socket::close()", LastError)); | |||||
| } | |||||
| } else { // If there was no error then | |||||
| LastError = 0; // reset the LastError value. | |||||
| } | |||||
| Handle = INVALID_SOCKET; // and reset the handle to INVALID. | |||||
| NonBlocking = false; // The default is Blocking. | |||||
| OpenSucceeded = false; // After close, forget we opened. | |||||
| } | |||||
| } | |||||
| hSocket Socket::getHandle() { // Returns the current Socket handle. | |||||
| return Handle; | |||||
| } | |||||
| bool Socket::isNonBlocking() { // Returns true if socket is NonBlocking | |||||
| return NonBlocking; | |||||
| } | |||||
| void Socket::makeNonBlocking() { // Sets the socket to NonBlocking mode. | |||||
| if(0 > Network.setNonBlocking(Handle)) { // Feed the call through Network. | |||||
| LastError = Network.getLastError(); // If it didn't work, go get the error. | |||||
| NonBlocking = false; // We are NOT NonBlocking. | |||||
| throw Networking::ControlError( // Throw a control error. | |||||
| Network.DescriptiveError( | |||||
| "Socket::makeNonBlocking()", LastError)); | |||||
| } else { | |||||
| NonBlocking = true; // If we didn't throw, we're ON. | |||||
| } | |||||
| } | |||||
| bool Socket::isReuseAddress() { return ReuseAddress; } // True if socket is set SO_REUSEADDR. | |||||
| bool Socket::isReuseAddress(bool set) { return (ReuseAddress = set); } // Changes SO_REUSEADDR setting. | |||||
| bool Socket::isOpen() { // True if the socket is open. | |||||
| return( | |||||
| INVALID_SOCKET != Handle && // A valid handle and | |||||
| true == OpenSucceeded // a successful open operation | |||||
| ); // means we're open. | |||||
| } | |||||
| int Socket::getLastError() { // Returns the last error for this socket. | |||||
| return LastError; | |||||
| } | |||||
| //// class TCPClient /////////////////////////////////////////////////////////// | |||||
| TCPClient::TCPClient(TCPListener& L, hSocket H, SocketAddress& A) : // How to create a TCPClient. | |||||
| MyListener(L) { // Capture our listener. | |||||
| Handle = H; // Capture the new socket handle. | |||||
| RemoteAddress = A; // Capture the client address. | |||||
| ReadPointer = ReadBuffer; // Set the read position to zero. | |||||
| DataLength = 0; // There is no data yet. | |||||
| OpenSucceeded = true; // We're getting an open socket. | |||||
| } | |||||
| TCPClient::~TCPClient() { // When destroying a TCPClient | |||||
| try{ if(isOpen()) close(); } catch(...) {} // silently close any open connections. | |||||
| } | |||||
| void TCPClient::open() { // We provide open() as unsupported. | |||||
| throw Networking::NotSupportedError( // Throw an exception if this is called. | |||||
| Network.DescriptiveError( | |||||
| "TCPClient::open()", LastError)); | |||||
| } | |||||
| bool TCPClient::ReadBufferIsEmpty() { // True if the ReadBuffer is empty. | |||||
| return (0 >= DataLength); // We can check that with DataLength. | |||||
| } | |||||
| void TCPClient::fillReadBuffer() { // Fills the buffer from the socket. | |||||
| LastError = 0; // Clear the LastError value. | |||||
| ReadPointer = ReadBuffer; // Reset the ReadPointer. | |||||
| DataLength = recv(Handle, ReadBuffer, sizeof(ReadBuffer), MSG_NOSIGNAL); // Try to read some data. | |||||
| if(0 >= DataLength) { // If there was an error then | |||||
| LastError = Network.getLastError(); // Grab the last error code. | |||||
| DataLength = 0; // Correct the DataLength. | |||||
| if(Network.WouldBlock(LastError)) { // If the error was WouldBlock then | |||||
| return; // simply return - it's ok. | |||||
| } else { // If it was a different error | |||||
| throw Networking::SocketReadError( // then throw a ReadError. | |||||
| Network.DescriptiveError( | |||||
| "TCPClient::fillReadBuffer()", LastError)); | |||||
| } | |||||
| } // If we succeeded then our ReadBuffer | |||||
| } // assembly is in good shape. | |||||
| bool TCPClient::isNonBlocking() { // Provided for MessagePort. | |||||
| return Socket::isNonBlocking(); | |||||
| } | |||||
| unsigned long TCPClient::getRemoteIP() { // Get remote IP as long. | |||||
| return RemoteAddress.getAddress(); | |||||
| } | |||||
| const char* TCPClient::getRemoteIP(char* str) { // Get IP as string. | |||||
| return RemoteAddress.getAddress(str); | |||||
| } | |||||
| unsigned short TCPClient::getRemotePort() { // Get remote Port as unsigned short. | |||||
| return RemoteAddress.getPort(); | |||||
| } | |||||
| const char* TCPClient::getRemotePort(char* str) { // Get Port as string. | |||||
| return RemoteAddress.getPort(str); | |||||
| } | |||||
| //// class TCPHost ///////////////////////////////////////////////////////////// | |||||
| TCPHost::~TCPHost() { // When destroying a TCPHost | |||||
| try{ if(isOpen()) close(); } catch(...) {} // silently close any open connection. | |||||
| } | |||||
| bool TCPHost::ReadBufferIsEmpty() { // True if the ReadBuffer is empty. | |||||
| return (0 >= DataLength); // We can check that with DataLength. | |||||
| } | |||||
| void TCPHost::fillReadBuffer() { // Fills the buffer from the socket. | |||||
| LastError = 0; // Clear the LastError value. | |||||
| ReadPointer = ReadBuffer; // Reset the ReadPointer. | |||||
| DataLength = recv(Handle, ReadBuffer, sizeof(ReadBuffer), MSG_NOSIGNAL); // Try to read some data. | |||||
| if(0 >= DataLength) { // If there was an error then | |||||
| LastError = Network.getLastError(); // Grab the last error code. | |||||
| DataLength = 0; // Correct the DataLength. | |||||
| if(Network.WouldBlock(LastError)) { // If the error was WouldBlock then | |||||
| return; // simply return - it's ok. | |||||
| } else { // If it was a different error | |||||
| throw Networking::SocketReadError( // then throw a ReadError. | |||||
| Network.DescriptiveError( | |||||
| "TCPHost::fillReadBuffer()", LastError)); | |||||
| } | |||||
| } // If we succeeded then our ReadBuffer | |||||
| } // assembly is in good shape. | |||||
| bool TCPHost::isNonBlocking() { // Provided for MessagePort. | |||||
| return Socket::isNonBlocking(); | |||||
| } | |||||
| //// class TCPListener ///////////////////////////////////////////////////////// | |||||
| TCPListener::~TCPListener() { // When destroying a TCPListener | |||||
| try{ close(); } catch(...) {} // silently close if not already done. | |||||
| } | |||||
| //// Platform Specific Stuff /////////////////////////////////////////////////// | //// Platform Specific Stuff /////////////////////////////////////////////////// | ||||
| // Error description handling for humans. | // Error description handling for humans. | ||||
| string Networking::DescriptiveError(string Msg, int Errno) { // Form a descriptive error w/ errno. | |||||
| string s = ""; // Message string. | |||||
| std::string Networking::DescriptiveError(std::string Msg, int Errno) { // Form a descriptive error w/ errno. | |||||
| std::string s = ""; // Message string. | |||||
| switch(Errno) { // Assign the appropriate message. | switch(Errno) { // Assign the appropriate message. | ||||
| case WSA_INVALID_HANDLE: s = "WSA_INVALID_HANDLE"; break; | case WSA_INVALID_HANDLE: s = "WSA_INVALID_HANDLE"; break; | ||||
| Msg.append(s); // then append it. | Msg.append(s); // then append it. | ||||
| } | } | ||||
| else { // If we don't know what Errno means | else { // If we don't know what Errno means | ||||
| ostringstream ErrNoMsg; // then say so and pass on Errno as | |||||
| std::ostringstream ErrNoMsg; // then say so and pass on Errno as | |||||
| ErrNoMsg << " UNKNOWN ErrorNumber = " << Errno; // well so someone can figure it out. | ErrNoMsg << " UNKNOWN ErrorNumber = " << Errno; // well so someone can figure it out. | ||||
| Msg.append(ErrNoMsg.str()); | Msg.append(ErrNoMsg.str()); | ||||
| } | } | ||||
| // Error description handling for humans. | // Error description handling for humans. | ||||
| string Networking::DescriptiveError(string Msg, int Errno) { // Form a descriptive error w/ errno. | |||||
| std::string Networking::DescriptiveError(std::string Msg, int Errno) { // Form a descriptive error w/ errno. | |||||
| Msg.append(" "); Msg.append(strerror(Errno)); | Msg.append(" "); Msg.append(strerror(Errno)); | ||||
| return Msg; | return Msg; | ||||
| }; | }; | ||||
| return IP; // Return it. | return IP; // Return it. | ||||
| } | } | ||||
| IP4Address::operator string() const { // Assign to a string. | |||||
| IP4Address::operator std::string() const { // Assign to a string. | |||||
| char stringbfr[IPStringBufferSize]; // Grab a temporary buffer. | char stringbfr[IPStringBufferSize]; // Grab a temporary buffer. | ||||
| memset(stringbfr, 0, sizeof(stringbfr)); // Null out it's space. | memset(stringbfr, 0, sizeof(stringbfr)); // Null out it's space. | ||||
| int a0, a1, a2, a3; // Grab some integers. | int a0, a1, a2, a3; // Grab some integers. | ||||
| splitIP(IP, a0, a1, a2, a3); // Split the IP in the IP4Address. | splitIP(IP, a0, a1, a2, a3); // Split the IP in the IP4Address. | ||||
| sprintf(stringbfr, "%d.%d.%d.%d", a0, a1, a2, a3); // Format the octets. | sprintf(stringbfr, "%d.%d.%d.%d", a0, a1, a2, a3); // Format the octets. | ||||
| return string(stringbfr); // Return a string. | |||||
| return std::string(stringbfr); // Return a string. | |||||
| } | } | ||||
| //// SocketAddress methods ///////////////////////////////////////////////////// | //// SocketAddress methods ///////////////////////////////////////////////////// | ||||
| if(!OpenStage2Complete) { // Do this stage only once. | if(!OpenStage2Complete) { // Do this stage only once. | ||||
| int result = // Bind our socket to the LocalAddress. | int result = // Bind our socket to the LocalAddress. | ||||
| ::bind( | |||||
| bind( | |||||
| Handle, | Handle, | ||||
| LocalAddress.getPtr_sockaddr(), | LocalAddress.getPtr_sockaddr(), | ||||
| LocalAddress.getAddressSize()); | LocalAddress.getAddressSize()); | ||||
| return NULL; // non blocking mode so we return | return NULL; // non blocking mode so we return | ||||
| } // NULL when we see them. | } // NULL when we see them. | ||||
| } | } | ||||
| // Set SO_NOSIGPIPE if needed | |||||
| if( // On some systems we may have to | |||||
| 0 != SO_NOSIGPIPE && // use SO_NOSIPIPE but if they offer | |||||
| 0 == MSG_NOSIGNAL // MSG_NOSIGNAL we prefer that instead. | |||||
| ) { | |||||
| int TurnedOn = 1; // Prepare to turn this option on. | |||||
| int result = // Set SO_NOSIGPIPE. | |||||
| setsockopt( | |||||
| NewHandle, | |||||
| SOL_SOCKET, | |||||
| SO_NOSIGPIPE, | |||||
| (char*) &TurnedOn, | |||||
| sizeof(TurnedOn)); | |||||
| if(0 > result) { // If there was an error then | |||||
| LastError = Network.getLastError(); // Capture the error information | |||||
| Network.closeSocket(NewHandle); // close the handle (avoid leaks) | |||||
| throw Networking::SocketSetSockOptError( // and throw a descriptive exception. | |||||
| Network.DescriptiveError( | |||||
| "TCPListener::acceptClient().setsockopt(SO_NOSIGPIPE)", LastError)); | |||||
| } | |||||
| } | |||||
| // Set SO_NOSIGPIPE if needed | |||||
| if( // On some systems we may have to | |||||
| 0 != SO_NOSIGPIPE && // use SO_NOSIPIPE but if they offer | |||||
| 0 == MSG_NOSIGNAL // MSG_NOSIGNAL we prefer that instead. | |||||
| ) { | |||||
| int TurnedOn = 1; // Prepare to turn this option on. | |||||
| int result = // Set SO_NOSIGPIPE. | |||||
| setsockopt( | |||||
| NewHandle, | |||||
| SOL_SOCKET, | |||||
| SO_NOSIGPIPE, | |||||
| (char*) &TurnedOn, | |||||
| sizeof(TurnedOn)); | |||||
| if(0 > result) { // If there was an error then | |||||
| LastError = Network.getLastError(); // Capture the error information | |||||
| Network.closeSocket(NewHandle); // close the handle (avoid leaks) | |||||
| throw Networking::SocketSetSockOptError( // and throw a descriptive exception. | |||||
| Network.DescriptiveError( | |||||
| "TCPListener::acceptClient().setsockopt(SO_NOSIGPIPE)", LastError)); | |||||
| } | |||||
| } | |||||
| // If things have gone well we can do what we came for. | // If things have gone well we can do what we came for. | ||||
| if(0 > size) // Watch out for bad sizes. | if(0 > size) // Watch out for bad sizes. | ||||
| throw Networking::SocketWriteError("TCPClient::transmit() 0 > size!"); | throw Networking::SocketWriteError("TCPClient::transmit() 0 > size!"); | ||||
| LastError = 0; // No errors yet. | |||||
| int ByteCount = 0; // No bytes sent yet this pass. | |||||
| LastError = 0; // No errors yet. | |||||
| int ByteCount = 0; // No bytes sent yet this pass. | |||||
| ByteCount = send(Handle, bfr, size, MSG_NOSIGNAL); // Try to send and capture the count. | ByteCount = send(Handle, bfr, size, MSG_NOSIGNAL); // Try to send and capture the count. | ||||
| LastError = Network.getLastError(); // Grab any error code. | |||||
| bool AnErrorOccurred = (0 > ByteCount); // How to know if an error occurred. | |||||
| const int NoBytesSent = 0; // This is our "Would Block" result. | |||||
| LastError = Network.getLastError(); // Grab any error code. | |||||
| bool AnErrorOccurred = (0 > ByteCount); // How to know if an error occurred. | |||||
| const int NoBytesSent = 0; // This is our "Would Block" result. | |||||
| if(AnErrorOccurred) { // If there was an error check it out. | if(AnErrorOccurred) { // If there was an error check it out. | ||||
| if(Network.WouldBlock(LastError)) { // If the error was "Would Block" then | if(Network.WouldBlock(LastError)) { // If the error was "Would Block" then | ||||
| return NoBytesSent; // return no bytes sent (try again). | return NoBytesSent; // return no bytes sent (try again). | ||||
| "TCPClient::transmit().send()", LastError)); | "TCPClient::transmit().send()", LastError)); | ||||
| } | } | ||||
| } | } | ||||
| return ByteCount; // Usually: return the sent byte count. | return ByteCount; // Usually: return the sent byte count. | ||||
| } | } | ||||
| LastError = 0; // Clear our LastError value. | LastError = 0; // Clear our LastError value. | ||||
| bool SuccessFlag = true; // Begin optimistically. | bool SuccessFlag = true; // Begin optimistically. | ||||
| // Set Socket Options | |||||
| // Set Socket Options | |||||
| if(!OpenStage1Complete) { // If we haven't done this yet: | if(!OpenStage1Complete) { // If we haven't done this yet: | ||||
| // Set SO_REUSEADDR if turned on | |||||
| // Set SO_REUSEADDR if turned on | |||||
| int ReuseAddress_Flag = (ReuseAddress? 1:0); // Setup an appropriate integer flag. | int ReuseAddress_Flag = (ReuseAddress? 1:0); // Setup an appropriate integer flag. | ||||
| int result = // Set SO_REUSEADDR before bind(). | int result = // Set SO_REUSEADDR before bind(). | ||||
| setsockopt( | setsockopt( | ||||
| Network.DescriptiveError( | Network.DescriptiveError( | ||||
| "TCPHost::open().setsockopt(SO_REUSEADDR)", LastError)); | "TCPHost::open().setsockopt(SO_REUSEADDR)", LastError)); | ||||
| } | } | ||||
| // Set SO_NOSIGPIPE if needed | |||||
| if( // On some systems we may have to | |||||
| 0 != SO_NOSIGPIPE && // use SO_NOSIPIPE but if they offer | |||||
| 0 == MSG_NOSIGNAL // MSG_NOSIGNAL we prefer that instead. | |||||
| ) { | |||||
| int TurnedOn = 1; // Prepare to turn this option on. | |||||
| int result = // Set SO_NOSIGPIPE. | |||||
| setsockopt( | |||||
| Handle, | |||||
| SOL_SOCKET, | |||||
| SO_NOSIGPIPE, | |||||
| (char*) &TurnedOn, | |||||
| sizeof(TurnedOn)); | |||||
| if(0 > result) { // If there was an error then | |||||
| SuccessFlag = false; // we did not succeed. | |||||
| LastError = Network.getLastError(); // Capture the error information and | |||||
| throw Networking::SocketSetSockOptError( // throw. | |||||
| Network.DescriptiveError( | |||||
| "TCPHost::open().setsockopt(SO_NOSIGPIPE)", LastError)); | |||||
| } | |||||
| } | |||||
| // Set SO_NOSIGPIPE if needed | |||||
| if( // On some systems we may have to | |||||
| 0 != SO_NOSIGPIPE && // use SO_NOSIPIPE but if they offer | |||||
| 0 == MSG_NOSIGNAL // MSG_NOSIGNAL we prefer that instead. | |||||
| ) { | |||||
| int TurnedOn = 1; // Prepare to turn this option on. | |||||
| int result = // Set SO_NOSIGPIPE. | |||||
| setsockopt( | |||||
| Handle, | |||||
| SOL_SOCKET, | |||||
| SO_NOSIGPIPE, | |||||
| (char*) &TurnedOn, | |||||
| sizeof(TurnedOn)); | |||||
| if(0 > result) { // If there was an error then | |||||
| SuccessFlag = false; // we did not succeed. | |||||
| LastError = Network.getLastError(); // Capture the error information and | |||||
| throw Networking::SocketSetSockOptError( // throw. | |||||
| Network.DescriptiveError( | |||||
| "TCPHost::open().setsockopt(SO_NOSIGPIPE)", LastError)); | |||||
| } | |||||
| } | |||||
| OpenStage1Complete = true; // Skip this section from now on. | OpenStage1Complete = true; // Skip this section from now on. | ||||
| } // Done with stage 1. | } // Done with stage 1. | ||||
| // End Platform Agnostic Stuff | // End Platform Agnostic Stuff | ||||
| //////////////////////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////////////////////// | ||||
| } // End namespace codedweller |
| // networking.hpp | // networking.hpp | ||||
| // Copyright (C) 2006-2009 MicroNeil Research Corporation. | |||||
| // | // | ||||
| // This program is part of the MicroNeil Research Open Library Project. For | |||||
| // more information go to http://www.microneil.com/OpenLibrary/index.html | |||||
| // Copyright (C) 2004-2020 MicroNeil Research Corporation. | |||||
| // | // | ||||
| // This program is free software; you can redistribute it and/or modify it | |||||
| // under the terms of the GNU General Public License as published by the | |||||
| // Free Software Foundation; either version 2 of the License, or (at your | |||||
| // option) any later version. | |||||
| // | |||||
| // This program is distributed in the hope that it will be useful, but WITHOUT | |||||
| // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |||||
| // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |||||
| // more details. | |||||
| // | |||||
| // You should have received a copy of the GNU General Public License along with | |||||
| // this program; if not, write to the Free Software Foundation, Inc., 59 Temple | |||||
| // Place, Suite 330, Boston, MA 02111-1307 USA | |||||
| //============================================================================== | |||||
| // This software is released under the MIT license. See LICENSE.TXT. | |||||
| // The networking module abstracts network communications and provides a set | // The networking module abstracts network communications and provides a set | ||||
| // of objects for handling most tasks. | |||||
| // 20080313 _M Refactored to throw proper runtime_error exceptions. | |||||
| // of objects for handling most tasks on both win* and *nix. | |||||
| // Include only once... | |||||
| #ifndef M_Networking | |||||
| #define M_Networking | |||||
| #pragma once | |||||
| #include <stdexcept> | #include <stdexcept> | ||||
| #include <iostream> | #include <iostream> | ||||
| #include <sstream> | #include <sstream> | ||||
| #include <cstring> | #include <cstring> | ||||
| using namespace std; | |||||
| #include <cstdlib> | #include <cstdlib> | ||||
| #include <cstdio> | #include <cstdio> | ||||
| #include <cerrno> | #include <cerrno> | ||||
| //// Windows headers... | //// Windows headers... | ||||
| #include <winsock2.h> | #include <winsock2.h> | ||||
| namespace codedweller { | |||||
| typedef int socklen_t; // Posix uses socklen_t so we mimic it. | typedef int socklen_t; // Posix uses socklen_t so we mimic it. | ||||
| typedef SOCKET hSocket; // Winx handles Socket is opaque. | typedef SOCKET hSocket; // Winx handles Socket is opaque. | ||||
| } // End namespace codedweller | |||||
| #else | #else | ||||
| //// GNU Headers... | //// GNU Headers... | ||||
| #include <unistd.h> | #include <unistd.h> | ||||
| #include <fcntl.h> | #include <fcntl.h> | ||||
| namespace codedweller { | |||||
| typedef int hSocket; // *nix uses int to handle a Socket. | typedef int hSocket; // *nix uses int to handle a Socket. | ||||
| const hSocket INVALID_SOCKET = -1; // -1 is the invalid Socket. | const hSocket INVALID_SOCKET = -1; // -1 is the invalid Socket. | ||||
| } // End namespace codedweller | |||||
| #endif | |||||
| namespace codedweller { | |||||
| //// Handling SIGPIPE ////////////////////////////////////////////////////////// | |||||
| #ifndef MSG_NOSIGNAL | |||||
| const int MSG_NOSIGNAL = 0; // Fake this if it isn't defined. | |||||
| #endif | |||||
| #ifndef SO_NOSIGPIPE | |||||
| const int SO_NOSIGPIPE = 0; // Fake this if it isn't defined. | |||||
| #endif | #endif | ||||
| //// Handling SIGPIPE ////////////////////////////////////////////////////////// | |||||
| #ifndef MSG_NOSIGNAL | |||||
| const int MSG_NOSIGNAL = 0; // Fake this if it isn't defined. | |||||
| #endif | |||||
| #ifndef SO_NOSIGPIPE | |||||
| const int SO_NOSIGPIPE = 0; // Fake this if it isn't defined. | |||||
| #endif | |||||
| //// Tuning and Constants ////////////////////////////////////////////////////// | //// Tuning and Constants ////////////////////////////////////////////////////// | ||||
| const unsigned long LOCALHOST = 0x7F000001; // 127.0.0.1 as an integer. | const unsigned long LOCALHOST = 0x7F000001; // 127.0.0.1 as an integer. | ||||
| IP4Address(const IP4Address&); // Constructor given an IP4Address | IP4Address(const IP4Address&); // Constructor given an IP4Address | ||||
| IP4Address(const char* newIP); // Construcing with a cstring. | IP4Address(const char* newIP); // Construcing with a cstring. | ||||
| IP4Address(const string& newIP); // Constructing with a cppstring. | |||||
| IP4Address(const std::string& newIP); // Constructing with a cppstring. | |||||
| IP4Address& operator=(const unsigned long int Right); // Convert from unsigned long int. | IP4Address& operator=(const unsigned long int Right); // Convert from unsigned long int. | ||||
| IP4Address& operator=(const char* Right); // Convert from c string. | IP4Address& operator=(const char* Right); // Convert from c string. | ||||
| IP4Address& operator=(const string& Right); // Convert from cpp string. | |||||
| IP4Address& operator=(const std::string& Right); // Convert from cpp string. | |||||
| operator unsigned long int() const; | operator unsigned long int() const; | ||||
| operator string() const; | |||||
| operator std::string() const; | |||||
| bool operator<(const IP4Address Right) const; // < Comparison. | bool operator<(const IP4Address Right) const; // < Comparison. | ||||
| bool operator>(const IP4Address Right) const; // > Comparison. | bool operator>(const IP4Address Right) const; // > Comparison. | ||||
| public: | public: | ||||
| class NotSupportedError : public runtime_error { // Thrown when something can't be done. | |||||
| public: NotSupportedError(const string& w):runtime_error(w) {} | |||||
| class NotSupportedError : public std::runtime_error { // Thrown when something can't be done. | |||||
| public: NotSupportedError(const std::string& w):runtime_error(w) {} | |||||
| }; | }; | ||||
| class InitializationError : public runtime_error { // Thrown if initialization fails. | |||||
| public: InitializationError(const string& w):runtime_error(w) {} | |||||
| class InitializationError : public std::runtime_error { // Thrown if initialization fails. | |||||
| public: InitializationError(const std::string& w):runtime_error(w) {} | |||||
| }; | }; | ||||
| class ControlError : public runtime_error { // Thrown if control functions fail. | |||||
| public: ControlError(const string& w):runtime_error(w) {} | |||||
| class ControlError : public std::runtime_error { // Thrown if control functions fail. | |||||
| public: ControlError(const std::string& w):runtime_error(w) {} | |||||
| }; | }; | ||||
| class SocketCreationError : public runtime_error { // Thrown if a call to socket() fails. | |||||
| public: SocketCreationError(const string& w):runtime_error(w) {} | |||||
| class SocketCreationError : public std::runtime_error { // Thrown if a call to socket() fails. | |||||
| public: SocketCreationError(const std::string& w):runtime_error(w) {} | |||||
| }; | }; | ||||
| class SocketSetSockOptError : public runtime_error { | |||||
| public: SocketSetSockOptError(const string& w):runtime_error(w) {} // Thrown if a call to setsockopt() fails. | |||||
| class SocketSetSockOptError : public std::runtime_error { // Thrown if a call to setsockopt() fails. | |||||
| public: SocketSetSockOptError(const std::string& w):runtime_error(w) {} | |||||
| }; | }; | ||||
| class SocketBindError : public runtime_error { // Thrown if a call to bind() fails. | |||||
| public: SocketBindError(const string& w):runtime_error(w) {} | |||||
| class SocketBindError : public std::runtime_error { // Thrown if a call to bind() fails. | |||||
| public: SocketBindError(const std::string& w):runtime_error(w) {} | |||||
| }; | }; | ||||
| class SocketListenError : public runtime_error { // Thrown if a call to listen() fails. | |||||
| public: SocketListenError(const string& w):runtime_error(w) {} | |||||
| class SocketListenError : public std::runtime_error { // Thrown if a call to listen() fails. | |||||
| public: SocketListenError(const std::string& w):runtime_error(w) {} | |||||
| }; | }; | ||||
| class SocketConnectError : public runtime_error { // Thrown if a call to connect() fails. | |||||
| public: SocketConnectError(const string& w):runtime_error(w) {} | |||||
| class SocketConnectError : public std::runtime_error { // Thrown if a call to connect() fails. | |||||
| public: SocketConnectError(const std::string& w):runtime_error(w) {} | |||||
| }; | }; | ||||
| class SocketAcceptError : public runtime_error { // Thrown if a call to accept() fails. | |||||
| public: SocketAcceptError(const string& w):runtime_error(w) {} | |||||
| class SocketAcceptError : public std::runtime_error { // Thrown if a call to accept() fails. | |||||
| public: SocketAcceptError(const std::string& w):runtime_error(w) {} | |||||
| }; | }; | ||||
| class SocketReadError : public runtime_error { // Thrown if a socket read call fails. | |||||
| public: SocketReadError(const string& w):runtime_error(w) {} | |||||
| class SocketReadError : public std::runtime_error { // Thrown if a socket read call fails. | |||||
| public: SocketReadError(const std::string& w):runtime_error(w) {} | |||||
| }; | }; | ||||
| class SocketWriteError : public runtime_error { // Thrown if a socket write call fails. | |||||
| public: SocketWriteError(const string& w):runtime_error(w) {} | |||||
| class SocketWriteError : public std::runtime_error { // Thrown if a socket write call fails. | |||||
| public: SocketWriteError(const std::string& w):runtime_error(w) {} | |||||
| }; | }; | ||||
| static string DescriptiveError(string Msg, int Errno); // Form a descriptive error w/ errno. | |||||
| static std::string DescriptiveError(std::string Msg, int Errno); // Form a descriptive error w/ errno. | |||||
| Networking(); | Networking(); | ||||
| ~Networking(); | ~Networking(); | ||||
| // End of UDPBroadcaster class | // End of UDPBroadcaster class | ||||
| //////////////////////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////////////////////// | ||||
| //// Include Inline methods and functions... | |||||
| #include "networking.inline.hpp" | |||||
| #endif | |||||
| // End include Networking.hpp only once... | |||||
| } // End namespace codedweller |
| // networking.inline.hpp | |||||
| // Copyright (C) 2006-2009 MicroNeil Research Corporation. | |||||
| // | |||||
| // This program is part of the MicroNeil Research Open Library Project. For | |||||
| // more information go to http://www.microneil.com/OpenLibrary/index.html | |||||
| // | |||||
| // This program is free software; you can redistribute it and/or modify it | |||||
| // under the terms of the GNU General Public License as published by the | |||||
| // Free Software Foundation; either version 2 of the License, or (at your | |||||
| // option) any later version. | |||||
| // | |||||
| // This program is distributed in the hope that it will be useful, but WITHOUT | |||||
| // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |||||
| // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |||||
| // more details. | |||||
| // | |||||
| // You should have received a copy of the GNU General Public License along with | |||||
| // this program; if not, write to the Free Software Foundation, Inc., 59 Temple | |||||
| // Place, Suite 330, Boston, MA 02111-1307 USA | |||||
| //============================================================================== | |||||
| // Inlined methods for Networking module. See networking.hpp for notes. | |||||
| //////////////////////////////////////////////////////////////////////////////// | |||||
| // Platform Specific | |||||
| //// Windows platform | |||||
| #if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64) | |||||
| inline int Networking::getLastError() { // In windows you get the last error | |||||
| return WSAGetLastError(); // from WSAGetLastError(); | |||||
| } | |||||
| inline int Networking::setNonBlocking(hSocket socket) { // Set a winsock to non-blocking | |||||
| unsigned long nonblocking = 1; // Create a flag... | |||||
| int result = 0; | |||||
| if(0 != ioctlsocket(socket, FIONBIO, &nonblocking)) { // Set the state of the socket. | |||||
| result = -1; // If that fails then return -1. | |||||
| } | |||||
| return result; // Show 'em my motto! | |||||
| } | |||||
| inline int Networking::closeSocket(hSocket socket) { // Close a socket in winsock | |||||
| return closesocket(socket); // wraps closesocket(). | |||||
| } | |||||
| inline bool Networking::WouldBlock(int ErrorCode) { // ErrorCode matches [WSA]EWOULDBLOCK. | |||||
| return (WSAEWOULDBLOCK == ErrorCode); | |||||
| } | |||||
| inline bool Networking::InProgress(int ErrorCode) { // ErrorCode matches [WSA]EINPROGRESS. | |||||
| return( // [WSA]EALREADY also returns true. | |||||
| WSAEINPROGRESS == ErrorCode || // In fact, on Win* platforms we could | |||||
| WSAEALREADY == ErrorCode || // get any of these when retesting | |||||
| WSAEWOULDBLOCK == ErrorCode || // open() for a connection. | |||||
| WSAEINVAL == ErrorCode | |||||
| ); | |||||
| } | |||||
| inline bool Networking::IsConnected(int ErrorCode) { // ErrorCode matches [WSA]EISCONN. | |||||
| return(WSAEISCONN == ErrorCode); | |||||
| } | |||||
| #else | |||||
| //// GNU platform | |||||
| inline int Networking::getLastError() { // In GNU you get the last error | |||||
| return errno; // from errno; | |||||
| } | |||||
| inline int Networking::setNonBlocking(hSocket socket) { // Set a socket to non-blocking | |||||
| int flags, result; // Grab a place to hold the flags. | |||||
| flags = fcntl(socket, F_GETFL, 0); // Get the current flags. | |||||
| result = fcntl(socket, F_SETFL, flags | O_NONBLOCK); // Set the NONBLOCK flag & return. | |||||
| return result; // Return the result. | |||||
| } | |||||
| inline int Networking::closeSocket(hSocket socket) { // Close a socket in GNU | |||||
| return close(socket); // wraps close(). | |||||
| } | |||||
| inline bool Networking::WouldBlock(int ErrorCode) { // ErrorCode matches [WSA]EWOULDBLOCK. | |||||
| return (EWOULDBLOCK == ErrorCode); | |||||
| } | |||||
| inline bool Networking::InProgress(int ErrorCode) { // ErrorCode matches [WSA]EINPROGRESS. | |||||
| return( // [WSA]EALREADY also returns true. | |||||
| EINPROGRESS == ErrorCode || | |||||
| EALREADY == ErrorCode | |||||
| ); | |||||
| } | |||||
| inline bool Networking::IsConnected(int ErrorCode) { // ErrorCode matches [WSA]EISCONN. | |||||
| return(EISCONN == ErrorCode); | |||||
| } | |||||
| #endif | |||||
| // End Platform Specific | |||||
| //////////////////////////////////////////////////////////////////////////////// | |||||
| // Begin Platform Agnostic | |||||
| //// class IP4Address ////////////////////////////////////////////////////////// | |||||
| inline IP4Address::IP4Address():IP(0){} // Blank constructor IP = 0.0.0.0 | |||||
| inline IP4Address::IP4Address(const unsigned long int newIP):IP(newIP){} // Constructor given unsigned long | |||||
| inline IP4Address::IP4Address(const IP4Address& newIP):IP(newIP.IP){} // Constructor given an IP4Address | |||||
| inline IP4Address::IP4Address(const char* newIP) { (*this) = newIP; } // Construcing with a cstring. | |||||
| inline IP4Address::IP4Address(const string& newIP) { (*this) = newIP; } // Constructing with a cppstring. | |||||
| inline IP4Address& | |||||
| IP4Address::operator=(const unsigned long int Right) { // Convert from unsigned long int. | |||||
| IP = Right; | |||||
| return *this; | |||||
| } | |||||
| inline IP4Address& IP4Address::operator=(const char* Right) { // Convert from c string. | |||||
| IP = ntohl(inet_addr(Right)); | |||||
| return *this; | |||||
| } | |||||
| inline IP4Address& IP4Address::operator=(const string& Right) { // Convert from cpp string. | |||||
| IP = ntohl(inet_addr(Right.c_str())); | |||||
| return *this; | |||||
| } | |||||
| inline bool IP4Address::operator<(const IP4Address Right) const { // < Comparison. | |||||
| return (IP < Right.IP); | |||||
| } | |||||
| inline bool IP4Address::operator>(const IP4Address Right) const { // > Comparison. | |||||
| return (IP > Right.IP); | |||||
| } | |||||
| inline bool IP4Address::operator==(const IP4Address Right) const { // == Comparison. | |||||
| return (IP == Right.IP); | |||||
| } | |||||
| inline bool IP4Address::operator!=(const IP4Address Right) const { // != Comparison. | |||||
| return (IP != Right.IP); | |||||
| } | |||||
| inline bool IP4Address::operator<=(const IP4Address Right) const { // <= Comparison. | |||||
| return (IP <= Right.IP); | |||||
| } | |||||
| inline bool IP4Address::operator>=(const IP4Address Right) const { // >= Comparison. | |||||
| return (IP >= Right.IP); | |||||
| } | |||||
| //// class SocketAddress /////////////////////////////////////////////////////// | |||||
| inline void SocketAddress::clear() { | |||||
| memset(&Address, 0, sizeof(Address)); // Zero out the address strcuture | |||||
| Address.sin_family = AF_INET; // Internet Address Family ip4 | |||||
| Address.sin_addr.s_addr = htonl(INADDR_ANY); // Any IP address | |||||
| Address.sin_port = 0; // Zero means any port. | |||||
| } | |||||
| inline SocketAddress::SocketAddress() { // Constructor sets up w/ wildcards | |||||
| clear(); // Conveniently, we can use clear() :-) | |||||
| } | |||||
| inline struct sockaddr_in* SocketAddress::getPtr_sockaddr_in() { // Returns a pointer to sockaddr_in. | |||||
| return &Address; // Simply return it's address. | |||||
| } | |||||
| inline struct sockaddr* SocketAddress::getPtr_sockaddr() { // Returns a pointer to sockaddr. | |||||
| return (struct sockaddr*) &Address; | |||||
| } | |||||
| inline socklen_t SocketAddress::getAddressSize() { | |||||
| return sizeof(Address); // Return the size of the structure. | |||||
| } | |||||
| inline void SocketAddress::setAddress(unsigned long ipAddress) { // Set the IP address from an unsigned int | |||||
| Address.sin_addr.s_addr = htonl(ipAddress); // Convert to network order and assign. | |||||
| } | |||||
| inline void SocketAddress::setAddress(char* ipString) { // Set the IP address from a cstring | |||||
| Address.sin_addr.s_addr = inet_addr(ipString); // Convert to number and assign. | |||||
| } | |||||
| inline unsigned long SocketAddress::getAddress() { // Get the IP address as an unsigned int | |||||
| return ntohl(Address.sin_addr.s_addr); // Convert to host order and return. | |||||
| } | |||||
| inline void SocketAddress::setPort(unsigned short port) { // Set the port address from an int | |||||
| Address.sin_port = htons(port); // Convert to network order and set. | |||||
| } | |||||
| inline void SocketAddress::setPort(char* port) { // Set the port address from a cstring | |||||
| setPort(atoi(port)); // Convert to int and set. | |||||
| } | |||||
| inline unsigned short SocketAddress::getPort() { // Get the port address as an unsigned int | |||||
| return ntohs(Address.sin_port); // Convert to host order and return. | |||||
| } | |||||
| inline const char* SocketAddress::getPort(char* str) { // Get the port address into a cstring. | |||||
| if(NULL == str) { // If the caller did not provide a | |||||
| str = PortStringBuffer; // buffer to use then we will use ours. | |||||
| } | |||||
| sprintf(str,"%d",getPort()); // Get the port and convert to cstring. | |||||
| return str; // Return the string we got. | |||||
| } | |||||
| //// class Socket ////////////////////////////////////////////////////////////// | |||||
| inline Socket::Socket() : // When starting up we are | |||||
| Handle(INVALID_SOCKET), OpenSucceeded(false) { // not yet valid. | |||||
| } | |||||
| inline Socket::~Socket() { // When shutting down, be sure | |||||
| if(INVALID_SOCKET != Handle) { // any open socket is closed without | |||||
| Network.closeSocket(Handle); // throwing any exceptions. | |||||
| } | |||||
| } | |||||
| inline void Socket::close() { // When we close, | |||||
| if(INVALID_SOCKET != Handle) { // If the handle is open then | |||||
| if(Network.closeSocket(Handle)) { // close the handle and check for error. | |||||
| LastError = Network.getLastError(); // If there was an error record it. | |||||
| if(!Network.WouldBlock(LastError)) { // If the error was not WOULDBLOCK | |||||
| throw Networking::ControlError( // then throw a ControlError exception. | |||||
| Network.DescriptiveError( | |||||
| "Socket::close()", LastError)); | |||||
| } | |||||
| } else { // If there was no error then | |||||
| LastError = 0; // reset the LastError value. | |||||
| } | |||||
| Handle = INVALID_SOCKET; // and reset the handle to INVALID. | |||||
| NonBlocking = false; // The default is Blocking. | |||||
| OpenSucceeded = false; // After close, forget we opened. | |||||
| } | |||||
| } | |||||
| inline hSocket Socket::getHandle() { // Returns the current Socket handle. | |||||
| return Handle; | |||||
| } | |||||
| inline bool Socket::isNonBlocking() { // Returns true if socket is NonBlocking | |||||
| return NonBlocking; | |||||
| } | |||||
| inline void Socket::makeNonBlocking() { // Sets the socket to NonBlocking mode. | |||||
| if(0 > Network.setNonBlocking(Handle)) { // Feed the call through Network. | |||||
| LastError = Network.getLastError(); // If it didn't work, go get the error. | |||||
| NonBlocking = false; // We are NOT NonBlocking. | |||||
| throw Networking::ControlError( // Throw a control error. | |||||
| Network.DescriptiveError( | |||||
| "Socket::makeNonBlocking()", LastError)); | |||||
| } else { | |||||
| NonBlocking = true; // If we didn't throw, we're ON. | |||||
| } | |||||
| } | |||||
| inline bool Socket::isReuseAddress() { return ReuseAddress; } // True if socket is set SO_REUSEADDR. | |||||
| inline bool Socket::isReuseAddress(bool set) { return (ReuseAddress = set); } // Changes SO_REUSEADDR setting. | |||||
| inline bool Socket::isOpen() { // True if the socket is open. | |||||
| return( | |||||
| INVALID_SOCKET != Handle && // A valid handle and | |||||
| true == OpenSucceeded // a successful open operation | |||||
| ); // means we're open. | |||||
| } | |||||
| inline int Socket::getLastError() { // Returns the last error for this socket. | |||||
| return LastError; | |||||
| } | |||||
| //// class TCPClient /////////////////////////////////////////////////////////// | |||||
| inline TCPClient::TCPClient(TCPListener& L, hSocket H, SocketAddress& A) : // How to create a TCPClient. | |||||
| MyListener(L) { // Capture our listener. | |||||
| Handle = H; // Capture the new socket handle. | |||||
| RemoteAddress = A; // Capture the client address. | |||||
| ReadPointer = ReadBuffer; // Set the read position to zero. | |||||
| DataLength = 0; // There is no data yet. | |||||
| OpenSucceeded = true; // We're getting an open socket. | |||||
| } | |||||
| inline TCPClient::~TCPClient() { // When destroying a TCPClient | |||||
| try{ if(isOpen()) close(); } catch(...) {} // silently close any open connections. | |||||
| } | |||||
| inline void TCPClient::open() { // We provide open() as unsupported. | |||||
| throw Networking::NotSupportedError( // Throw an exception if this is called. | |||||
| Network.DescriptiveError( | |||||
| "TCPClient::open()", LastError)); | |||||
| } | |||||
| inline bool TCPClient::ReadBufferIsEmpty() { // True if the ReadBuffer is empty. | |||||
| return (0 >= DataLength); // We can check that with DataLength. | |||||
| } | |||||
| inline void TCPClient::fillReadBuffer() { // Fills the buffer from the socket. | |||||
| LastError = 0; // Clear the LastError value. | |||||
| ReadPointer = ReadBuffer; // Reset the ReadPointer. | |||||
| DataLength = recv(Handle, ReadBuffer, sizeof(ReadBuffer), MSG_NOSIGNAL); // Try to read some data. | |||||
| if(0 >= DataLength) { // If there was an error then | |||||
| LastError = Network.getLastError(); // Grab the last error code. | |||||
| DataLength = 0; // Correct the DataLength. | |||||
| if(Network.WouldBlock(LastError)) { // If the error was WouldBlock then | |||||
| return; // simply return - it's ok. | |||||
| } else { // If it was a different error | |||||
| throw Networking::SocketReadError( // then throw a ReadError. | |||||
| Network.DescriptiveError( | |||||
| "TCPClient::fillReadBuffer()", LastError)); | |||||
| } | |||||
| } // If we succeeded then our ReadBuffer | |||||
| } // assembly is in good shape. | |||||
| inline bool TCPClient::isNonBlocking() { // Provided for MessagePort. | |||||
| return Socket::isNonBlocking(); | |||||
| } | |||||
| inline unsigned long TCPClient::getRemoteIP() { // Get remote IP as long. | |||||
| return RemoteAddress.getAddress(); | |||||
| } | |||||
| inline const char* TCPClient::getRemoteIP(char* str) { // Get IP as string. | |||||
| return RemoteAddress.getAddress(str); | |||||
| } | |||||
| inline unsigned short TCPClient::getRemotePort() { // Get remote Port as unsigned short. | |||||
| return RemoteAddress.getPort(); | |||||
| } | |||||
| inline const char* TCPClient::getRemotePort(char* str) { // Get Port as string. | |||||
| return RemoteAddress.getPort(str); | |||||
| } | |||||
| //// class TCPHost ///////////////////////////////////////////////////////////// | |||||
| inline TCPHost::~TCPHost() { // When destroying a TCPHost | |||||
| try{ if(isOpen()) close(); } catch(...) {} // silently close any open connection. | |||||
| } | |||||
| inline bool TCPHost::ReadBufferIsEmpty() { // True if the ReadBuffer is empty. | |||||
| return (0 >= DataLength); // We can check that with DataLength. | |||||
| } | |||||
| inline void TCPHost::fillReadBuffer() { // Fills the buffer from the socket. | |||||
| LastError = 0; // Clear the LastError value. | |||||
| ReadPointer = ReadBuffer; // Reset the ReadPointer. | |||||
| DataLength = recv(Handle, ReadBuffer, sizeof(ReadBuffer), MSG_NOSIGNAL); // Try to read some data. | |||||
| if(0 >= DataLength) { // If there was an error then | |||||
| LastError = Network.getLastError(); // Grab the last error code. | |||||
| DataLength = 0; // Correct the DataLength. | |||||
| if(Network.WouldBlock(LastError)) { // If the error was WouldBlock then | |||||
| return; // simply return - it's ok. | |||||
| } else { // If it was a different error | |||||
| throw Networking::SocketReadError( // then throw a ReadError. | |||||
| Network.DescriptiveError( | |||||
| "TCPHost::fillReadBuffer()", LastError)); | |||||
| } | |||||
| } // If we succeeded then our ReadBuffer | |||||
| } // assembly is in good shape. | |||||
| inline bool TCPHost::isNonBlocking() { // Provided for MessagePort. | |||||
| return Socket::isNonBlocking(); | |||||
| } | |||||
| //// class TCPListener ///////////////////////////////////////////////////////// | |||||
| inline TCPListener::~TCPListener() { // When destroying a TCPListener | |||||
| try{ close(); } catch(...) {} // silently close if not already done. | |||||
| } |
| // onetimepad.cpp | // onetimepad.cpp | ||||
| // Copyright (C) 2006-2007 MicroNeil Research Corporation | |||||
| // | |||||
| // Copyright (C) 2006-2020 MicroNeil Research Corporation. | |||||
| // | |||||
| // This software is released under the MIT license. See LICENSE.TXT. | |||||
| #include "onetimepad.hpp" | #include "onetimepad.hpp" | ||||
| #include "timing.hpp" | #include "timing.hpp" | ||||
| #include <windows.h> | #include <windows.h> | ||||
| #include <wincrypt.h> | #include <wincrypt.h> | ||||
| namespace codedweller { | |||||
| PadBuffer OneTimePad::Entropy(int Length) { // Get a PadBuffer full of randomness. | PadBuffer OneTimePad::Entropy(int Length) { // Get a PadBuffer full of randomness. | ||||
| PadBuffer Buffer(Length, 0); // Start by initializing the buffer. | PadBuffer Buffer(Length, 0); // Start by initializing the buffer. | ||||
| HCRYPTPROV provider = 0; // We will need a handle for the source. | HCRYPTPROV provider = 0; // We will need a handle for the source. | ||||
| return Buffer; // Return the data we got. | return Buffer; // Return the data we got. | ||||
| } | } | ||||
| } // End namespace codddweller | |||||
| #else | #else | ||||
| //// *NIX Strong Entropy Source == /dev/urandom //////////////////////////////// | //// *NIX Strong Entropy Source == /dev/urandom //////////////////////////////// | ||||
| #include <fstream> | #include <fstream> | ||||
| namespace codedweller { | |||||
| PadBuffer OneTimePad::Entropy(int Length) { // Get Length bytes of strong entropy. | PadBuffer OneTimePad::Entropy(int Length) { // Get Length bytes of strong entropy. | ||||
| PadBuffer Buffer(Length, 0); // Initialize a buffer to hold them. | PadBuffer Buffer(Length, 0); // Initialize a buffer to hold them. | ||||
| try { // Handle this in a try block. | try { // Handle this in a try block. | ||||
| ifstream Source("/dev/urandom", ios::binary); // Open /dev/urandom if possible. | |||||
| std::ifstream Source("/dev/urandom", std::ios::binary); // Open /dev/urandom if possible. | |||||
| Source.read(reinterpret_cast<char*>(&Buffer[0]), Length); // Read data into the buffer. | Source.read(reinterpret_cast<char*>(&Buffer[0]), Length); // Read data into the buffer. | ||||
| if(!Source.bad() && Source.gcount() == Length) { // If we got what we came for then | if(!Source.bad() && Source.gcount() == Length) { // If we got what we came for then | ||||
| StrongEntropyFlag = true; // we have strong cryptography. | StrongEntropyFlag = true; // we have strong cryptography. | ||||
| return Buffer; // Return the buffer. | return Buffer; // Return the buffer. | ||||
| } | } | ||||
| } // End namespace codedweller | |||||
| #endif | #endif | ||||
| // End Platform Specific Bits | // End Platform Specific Bits | ||||
| //////////////////////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////////////////////// | ||||
| namespace codedweller { | |||||
| // Lightweight entropy is built from a combination of the time in ms UTC that | // Lightweight entropy is built from a combination of the time in ms UTC that | ||||
| // the application was started, the number of milliseconds since that time in | // the application was started, the number of milliseconds since that time in | ||||
| // milliseconds, the number and times of calls to addLightweightEntropy(), and | // milliseconds, the number and times of calls to addLightweightEntropy(), and | ||||
| CombinedFill = CombinedFill ^ LightweightEntropyBuffer; // Pick up some previous state entropy. | CombinedFill = CombinedFill ^ LightweightEntropyBuffer; // Pick up some previous state entropy. | ||||
| unsigned char* PrimerBuffer = (unsigned char*) &CombinedFill; // Treat the value as a bunch of bytes. | unsigned char* PrimerBuffer = (unsigned char*) &CombinedFill; // Treat the value as a bunch of bytes. | ||||
| unsigned char* EntropyBuffer = (unsigned char*) &LightweightEntropyBuffer; // Likewise with the entropy buffer. | unsigned char* EntropyBuffer = (unsigned char*) &LightweightEntropyBuffer; // Likewise with the entropy buffer. | ||||
| for(int i = 0; i < sizeof(msclock); i++) { // Fold bytes into the mangler one | |||||
| for(size_t i = 0; i < sizeof(msclock); i++) { // Fold bytes into the mangler one | |||||
| EntropyBuffer[i] += // byte at a time, capturing the | EntropyBuffer[i] += // byte at a time, capturing the | ||||
| PadGenerator.Encrypt( // the results and using one extra | PadGenerator.Encrypt( // the results and using one extra | ||||
| PadGenerator.Encrypt(PrimerBuffer[i])); // round per byte to increase the | PadGenerator.Encrypt(PrimerBuffer[i])); // round per byte to increase the | ||||
| void OneTimePad::addEntropy() { // Add strong entropy if available. | void OneTimePad::addEntropy() { // Add strong entropy if available. | ||||
| PadBuffer Fill = Entropy(); // Grab the entropy bits to add. | PadBuffer Fill = Entropy(); // Grab the entropy bits to add. | ||||
| for(int i = 0; i < Fill.size(); i++) { // Pump them in one byte at a | |||||
| for(size_t i = 0; i < Fill.size(); i++) { // Pump them in one byte at a | |||||
| PadGenerator.Encrypt( // time and then run an extra | PadGenerator.Encrypt( // time and then run an extra | ||||
| PadGenerator.Encrypt(Fill.at(i))); // round per byte to increase the | PadGenerator.Encrypt(Fill.at(i))); // round per byte to increase the | ||||
| } // amount of guessing an attacker | } // amount of guessing an attacker | ||||
| void OneTimePad::addEntropy(PadBuffer Entropy) { // Add entropy from a given source. | void OneTimePad::addEntropy(PadBuffer Entropy) { // Add entropy from a given source. | ||||
| addLightweightEntropy(); // Start with some lightweight entropy. | addLightweightEntropy(); // Start with some lightweight entropy. | ||||
| for(int i = 0; i < Entropy.size(); i++) { // Then loop through the provided | |||||
| for(size_t i = 0; i < Entropy.size(); i++) { // Then loop through the provided | |||||
| PadGenerator.Encrypt( // entropy and mix it in with one | PadGenerator.Encrypt( // entropy and mix it in with one | ||||
| PadGenerator.Encrypt(Entropy.at(i))); // extra round per byte to increase | PadGenerator.Encrypt(Entropy.at(i))); // extra round per byte to increase | ||||
| } // the amount of guessing an attacker | } // the amount of guessing an attacker | ||||
| } // initial Mangler state. | } // initial Mangler state. | ||||
| } // The OneTimePad object is ready. | } // The OneTimePad object is ready. | ||||
| } // End namespace codedweller |
| // onetimepad.hpp | // onetimepad.hpp | ||||
| // Copyright (C) 2006 - 2007 MicroNeil Research Corporation | |||||
| // | |||||
| // Copyright (C) 2006-2020 MicroNeil Research Corporation. | |||||
| // | |||||
| // This software is released under the MIT license. See LICENSE.TXT. | |||||
| // | // | ||||
| // This module leverages the Mangler encryption engine to create | // This module leverages the Mangler encryption engine to create | ||||
| // cryptographically strong one-time pads and random numbers upon request. | // cryptographically strong one-time pads and random numbers upon request. | ||||
| // started. Additional entropy can be provided by the application or again from | // started. Additional entropy can be provided by the application or again from | ||||
| // one of the core entropy generators (/dev/urandom or CryptGenRandom). | // one of the core entropy generators (/dev/urandom or CryptGenRandom). | ||||
| #ifndef onetimepad_included | |||||
| #define onetimepad_included | |||||
| #pragma once | |||||
| #include <vector> | #include <vector> | ||||
| #include "mangler.hpp" | #include "mangler.hpp" | ||||
| using namespace std; | |||||
| namespace codedweller { | |||||
| typedef vector<unsigned char> PadBuffer; | |||||
| typedef std::vector<unsigned char> PadBuffer; | |||||
| class OneTimePad { // One Time Pad generator. | class OneTimePad { // One Time Pad generator. | ||||
| private: | private: | ||||
| }; | }; | ||||
| #endif | |||||
| } // End namespace codedweller |
| // threading.cpp | // threading.cpp | ||||
| // | // | ||||
| // (C) 2006 - 2009 MicroNeil Research Corporation. | |||||
| // Copyright (C) 2006-2020 MicroNeil Research Corporation. | |||||
| // | // | ||||
| // This program is part of the MicroNeil Research Open Library Project. For | |||||
| // more information go to http://www.microneil.com/OpenLibrary/index.html | |||||
| // | |||||
| // This program is free software; you can redistribute it and/or modify it | |||||
| // under the terms of the GNU General Public License as published by the | |||||
| // Free Software Foundation; either version 2 of the License, or (at your | |||||
| // option) any later version. | |||||
| // | |||||
| // This program is distributed in the hope that it will be useful, but WITHOUT | |||||
| // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |||||
| // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |||||
| // more details. | |||||
| // | |||||
| // You should have received a copy of the GNU General Public License along with | |||||
| // this program; if not, write to the Free Software Foundation, Inc., 59 Temple | |||||
| // Place, Suite 330, Boston, MA 02111-1307 USA | |||||
| // For details on the Threading module and development history see threading.hpp | |||||
| // This software is released under the MIT license. See LICENSE.TXT. | |||||
| #include "threading.hpp" | #include "threading.hpp" | ||||
| using namespace std; // Introduce std namespace. | |||||
| namespace codedweller { | |||||
| ThreadManager Threads; // Master thread manager. | ThreadManager Threads; // Master thread manager. | ||||
| ScopeMutex ThereCanBeOnlyOne(MyMutex); // Protect our set -- a moment in time. | ScopeMutex ThereCanBeOnlyOne(MyMutex); // Protect our set -- a moment in time. | ||||
| ThreadStatusReport Answer; // Create our vector to hold the report. | ThreadStatusReport Answer; // Create our vector to hold the report. | ||||
| for( // Loop through all of the Threads. | for( // Loop through all of the Threads. | ||||
| set<Thread*>::iterator iT = KnownThreads.begin(); | |||||
| std::set<Thread*>::iterator iT = KnownThreads.begin(); | |||||
| iT != KnownThreads.end(); iT++ | iT != KnownThreads.end(); iT++ | ||||
| ) { // Grab each Threads' report. | ) { // Grab each Threads' report. | ||||
| Thread& X = *(*iT); // Handy reference to the Thread. | Thread& X = *(*iT); // Handy reference to the Thread. | ||||
| bool Thread::isBad() { return BadFlag; } // Return BadFlag state. | bool Thread::isBad() { return BadFlag; } // Return BadFlag state. | ||||
| const string Thread::MyFault() { return BadWhat; } // Return exception Bad fault if any. | |||||
| const string Thread::MyName() { return MyThreadName; } // Return the instance name if any. | |||||
| const std::string Thread::MyFault() { return BadWhat; } // Return exception Bad fault if any. | |||||
| const std::string Thread::MyName() { return MyThreadName; } // Return the instance name if any. | |||||
| const ThreadType& Thread::MyType() { return MyThreadType; } // Return the instance Thread Type. | const ThreadType& Thread::MyType() { return MyThreadType; } // Return the instance Thread Type. | ||||
| const ThreadState& Thread::MyState() { return (*MyThreadState); } // Thread state for this instance. | const ThreadState& Thread::MyState() { return (*MyThreadState); } // Thread state for this instance. | ||||
| CurrentThreadState(ThreadStarted); // Set the running state. | CurrentThreadState(ThreadStarted); // Set the running state. | ||||
| myTask(); // myTask() is called. | myTask(); // myTask() is called. | ||||
| } // myTask() should handle exceptions. | } // myTask() should handle exceptions. | ||||
| catch(exception& e) { // Unhandled exceptions are informative: | |||||
| catch(const std::exception& e) { // Unhandled exceptions are informative: | |||||
| BadFlag = true; // They mean the thread went bad but | BadFlag = true; // They mean the thread went bad but | ||||
| BadWhat = e.what(); // we have an idea what went wrong. | BadWhat = e.what(); // we have an idea what went wrong. | ||||
| } // We shouldn't get other kinds of | } // We shouldn't get other kinds of | ||||
| CurrentThreadState(ThreadInitialized); // Set our initialized state. | CurrentThreadState(ThreadInitialized); // Set our initialized state. | ||||
| } | } | ||||
| Thread::Thread(const ThreadType& T, const string N) : // Construct with specific Type/Name | |||||
| Thread::Thread(const ThreadType& T, const std::string N) : // Construct with specific Type/Name | |||||
| MyThreadType(T), // Use generic Thread Type. | MyThreadType(T), // Use generic Thread Type. | ||||
| MyThreadName(N), // Use a generic Thread Name. | MyThreadName(N), // Use a generic Thread Name. | ||||
| MyThread(NULL), // Null the thread handle. | MyThread(NULL), // Null the thread handle. | ||||
| CurrentThreadState(ThreadInitialized); // Set our initialized state. | CurrentThreadState(ThreadInitialized); // Set our initialized state. | ||||
| } | } | ||||
| Thread::Thread(const ThreadType& T, const string N) : // POSIX Specific Thread Constructor. | |||||
| Thread::Thread(const ThreadType& T, const std::string N) : // POSIX Specific Thread Constructor. | |||||
| MyThreadType(T), // Use a generic Thread Type. | MyThreadType(T), // Use a generic Thread Type. | ||||
| MyThreadName(N), // Use a generic Thread Name. | MyThreadName(N), // Use a generic Thread Name. | ||||
| RunningFlag(false), // Can't be running yet. | RunningFlag(false), // Can't be running yet. | ||||
| // End Production Gateway | // End Production Gateway | ||||
| //////////////////////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////////////////////// | ||||
| } // End namespace codedweller |
| // threading.hpp | // threading.hpp | ||||
| // | // | ||||
| // (C) 2006 - 2009 MicroNeil Research Corporation. | |||||
| // Copyright (C) 2004-2020 MicroNeil Research Corporation. | |||||
| // | // | ||||
| // This program is part of the MicroNeil Research Open Library Project. For | |||||
| // more information go to http://www.microneil.com/OpenLibrary/index.html | |||||
| // | |||||
| // This program is free software; you can redistribute it and/or modify it | |||||
| // under the terms of the GNU General Public License as published by the | |||||
| // Free Software Foundation; either version 2 of the License, or (at your | |||||
| // option) any later version. | |||||
| // | |||||
| // This program is distributed in the hope that it will be useful, but WITHOUT | |||||
| // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |||||
| // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |||||
| // more details. | |||||
| // | |||||
| // You should have received a copy of the GNU General Public License along with | |||||
| // this program; if not, write to the Free Software Foundation, Inc., 59 Temple | |||||
| // Place, Suite 330, Boston, MA 02111-1307 USA | |||||
| // This software is released under the MIT license. See LICENSE.TXT. | |||||
| // The "Threading" module is a basic, cross-platform, multi-threading tool kit. | // The "Threading" module is a basic, cross-platform, multi-threading tool kit. | ||||
| // The differences between posix compatible systems and win32 based systems are | // The differences between posix compatible systems and win32 based systems are | ||||
| // here are designed to cover all of the basics efficiently while hiding the | // here are designed to cover all of the basics efficiently while hiding the | ||||
| // required under-cover work. | // required under-cover work. | ||||
| // A lot of this module is coded here in the header with the inline keyword | |||||
| // because it is likely that the more basic objects can be efficiently compiled | |||||
| // as inline abstractions to native calls. Really basic systems won't need | |||||
| // anything beyond what is in this file. | |||||
| // 20070202.1601 _M Further research has suggested that using a Semaphore in | |||||
| // WIN32 environments in place of a CRITICAL_SECTION may provide the best | |||||
| // performance and stability on all platforms. Specifically, SMP platforms may | |||||
| // race and waste resources with CRITICAL_SECTIONs and in those cases it is | |||||
| // recommended that the CRITICAL_SECTIONs may be "throttled" using Semaphores | |||||
| // to limit the number of threads that may contend for a critical section. It | |||||
| // is also suggested that if the Semaphore has an initialization value of 1 | |||||
| // the CRITICAL_SECTION is redundant. So this code has been modified to do | |||||
| // precisely that! | |||||
| // | |||||
| // This new version also includes a ProductionGateway object that simplifies | |||||
| // the producer/consumer model. The object keeps track of the number of calls | |||||
| // to produce() and consume() and ensures that threads will block on consume() | |||||
| // until a sufficient number of calls to produce() are made. That is, for every | |||||
| // one call to produce(), a call to consume() will be allowed to proceed. The | |||||
| // object also allows for the potentially asynchronous nature of these calls. | |||||
| // 20070530.1751 _M Added top level exception handling in threads along with | |||||
| // isRunning() and isBad() methods. | |||||
| // 20060528.1647 _M All of the basics are complete and tested on both WIN32 and | |||||
| // RHEL4 single and multiple processors. | |||||
| // Include MNR_threading Once Only ============================================= | |||||
| #ifndef MNR_threading | |||||
| #define MNR_threading | |||||
| #pragma once | |||||
| #include <set> | #include <set> | ||||
| #include <vector> | #include <vector> | ||||
| #include <string> | #include <string> | ||||
| #include <queue> | |||||
| #include "faults.hpp" | |||||
| #include <queue> | |||||
| #include "faults.hpp" | |||||
| using namespace std; | |||||
| namespace codedweller { | |||||
| class ThreadManager; // ThreadManager does exist. | class ThreadManager; // ThreadManager does exist. | ||||
| extern ThreadManager Threads; // Master thread manager. | extern ThreadManager Threads; // Master thread manager. | ||||
| class ThreadState { // Thread State Object. | class ThreadState { // Thread State Object. | ||||
| public: | public: | ||||
| const string Name; // Text name of thread descriptor. | |||||
| ThreadState(string N) : Name(N) {} // Constructor requires text name. | |||||
| const std::string Name; // Text name of thread descriptor. | |||||
| ThreadState(std::string N) : Name(N) {} // Constructor requires text name. | |||||
| }; | }; | ||||
| // ThreadType objects are constant static objects defined for each Thread class | // ThreadType objects are constant static objects defined for each Thread class | ||||
| class ThreadType { | class ThreadType { | ||||
| public: | public: | ||||
| const string Name; | |||||
| ThreadType(string N) : Name(N) {} | |||||
| const std::string Name; | |||||
| ThreadType(std::string N) : Name(N) {} | |||||
| }; | }; | ||||
| class Thread; // There is such thing as a Thread. | class Thread; // There is such thing as a Thread. | ||||
| Thread* Pointer; // A pointer to the thread. | Thread* Pointer; // A pointer to the thread. | ||||
| ThreadType* Type; // A descriptor of it's type. | ThreadType* Type; // A descriptor of it's type. | ||||
| ThreadState* State; // A descriptor of it's state. | ThreadState* State; // A descriptor of it's state. | ||||
| string Name; // Name of the thread if any. | |||||
| std::string Name; // Name of the thread if any. | |||||
| bool isRunning; // True if the thread is running. | bool isRunning; // True if the thread is running. | ||||
| bool isBad; // True if the thread is bad. | bool isBad; // True if the thread is bad. | ||||
| string Fault; // Bad Thread's Fault if any. | |||||
| std::string Fault; // Bad Thread's Fault if any. | |||||
| public: | public: | ||||
| ThreadStatusRecord( // Initialize all items. | ThreadStatusRecord( // Initialize all items. | ||||
| ThreadState& S, | ThreadState& S, | ||||
| bool R, | bool R, | ||||
| bool B, | bool B, | ||||
| string F, | |||||
| string N | |||||
| std::string F, | |||||
| std::string N | |||||
| ) : | ) : | ||||
| Pointer(P), | Pointer(P), | ||||
| Type(&T), | Type(&T), | ||||
| State(&S), | State(&S), | ||||
| Name(N), | |||||
| Name(N), | |||||
| isRunning(R), | isRunning(R), | ||||
| isBad(B), | isBad(B), | ||||
| Fault(F) | Fault(F) | ||||
| isRunning = Right.isRunning; | isRunning = Right.isRunning; | ||||
| isBad = Right.isBad; | isBad = Right.isBad; | ||||
| Fault = Right.Fault; | Fault = Right.Fault; | ||||
| Name = Right.Name; | |||||
| Name = Right.Name; | |||||
| return *this; | return *this; | ||||
| } | } | ||||
| const ThreadState& getState() { return *State; } | const ThreadState& getState() { return *State; } | ||||
| bool getRunning() { return isRunning; } | bool getRunning() { return isRunning; } | ||||
| bool getBad() { return isBad; } | bool getBad() { return isBad; } | ||||
| string getFault() { return Fault; } | |||||
| string getName() { return Name; } | |||||
| std::string getFault() { return Fault; } | |||||
| std::string getName() { return Name; } | |||||
| }; | }; | ||||
| typedef vector<ThreadStatusRecord> ThreadStatusReport; // Status report type. | |||||
| typedef std::vector<ThreadStatusRecord> ThreadStatusReport; // Status report type. | |||||
| // End ThreadDescriptor | // End ThreadDescriptor | ||||
| //////////////////////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////////////////////// | ||||
| } // End namespace codedweller | |||||
| //////////////////////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////////////////////// | ||||
| // Win32 / POSIX abstractions | // Win32 / POSIX abstractions | ||||
| #include <windows.h> | #include <windows.h> | ||||
| #include <process.h> | #include <process.h> | ||||
| namespace codedweller { | |||||
| typedef HANDLE thread_primative; // The WIN32 thread primative abstracts | typedef HANDLE thread_primative; // The WIN32 thread primative abstracts | ||||
| // HANDLE | // HANDLE | ||||
| SwitchToThread(); // we call SwitchToThread(); | SwitchToThread(); // we call SwitchToThread(); | ||||
| } | } | ||||
| } // End namespace codedweller | |||||
| #else | #else | ||||
| // When in POSIX land... | // When in POSIX land... | ||||
| #include <pthread.h> | #include <pthread.h> | ||||
| #include <sched.h> | #include <sched.h> | ||||
| namespace codedweller { | |||||
| typedef pthread_t thread_primative; // The POSIX thread primative abstracts | typedef pthread_t thread_primative; // The POSIX thread primative abstracts | ||||
| // pthread_t | // pthread_t | ||||
| sched_yield(); // we call sched_yield(); | sched_yield(); // we call sched_yield(); | ||||
| } | } | ||||
| } // End namespace codedweller | |||||
| #endif | #endif | ||||
| // End Win32 / POSIX abstractions | // End Win32 / POSIX abstractions | ||||
| //////////////////////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////////////////////// | ||||
| namespace codedweller { | |||||
| //////////////////////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////////////////////// | ||||
| // The Thread class gets extended to do any specific work. The pure virtual | // The Thread class gets extended to do any specific work. The pure virtual | ||||
| // function MyTask is overloaded by the derived class to define that work. It | // function MyTask is overloaded by the derived class to define that work. It | ||||
| protected: | protected: | ||||
| const ThreadType& MyThreadType; // Identify thread type. | const ThreadType& MyThreadType; // Identify thread type. | ||||
| const string MyThreadName; // Name string of this instance. | |||||
| const std::string MyThreadName; // Name string of this instance. | |||||
| thread_primative MyThread; // Abstracted thread. | thread_primative MyThread; // Abstracted thread. | ||||
| bool RunningFlag; // True when thread is in myTask() | bool RunningFlag; // True when thread is in myTask() | ||||
| bool BadFlag; // True when myTask() throws! | bool BadFlag; // True when myTask() throws! | ||||
| string BadWhat; // Bad exception what() if any. | |||||
| std::string BadWhat; // Bad exception what() if any. | |||||
| void CurrentThreadState(const ThreadState& TS); // Set thread state. | void CurrentThreadState(const ThreadState& TS); // Set thread state. | ||||
| public: | public: | ||||
| Thread(); // Constructor (just in case) | Thread(); // Constructor (just in case) | ||||
| Thread(const ThreadType& T, string N); // Construct with specific Type/Name | |||||
| Thread(const ThreadType& T, std::string N); // Construct with specific Type/Name | |||||
| virtual ~Thread(); // Destructor (just in case) | virtual ~Thread(); // Destructor (just in case) | ||||
| void run(); // Method to launch this thread. | void run(); // Method to launch this thread. | ||||
| bool isRunning(); // Return the Running flag state. | bool isRunning(); // Return the Running flag state. | ||||
| bool isBad(); // Return the Bad flag state. | bool isBad(); // Return the Bad flag state. | ||||
| const string MyFault(); // Return exception Bad fault if any. | |||||
| const std::string MyFault(); // Return exception Bad fault if any. | |||||
| const string MyName(); // The thread's name. | |||||
| const std::string MyName(); // The thread's name. | |||||
| const ThreadType& MyType(); // Thread type for this thread. | const ThreadType& MyType(); // Thread type for this thread. | ||||
| const ThreadState& MyState(); // Returns the current thread state. | const ThreadState& MyState(); // Returns the current thread state. | ||||
| const ThreadState& CurrentThreadState(); // Returns the current thread state. | const ThreadState& CurrentThreadState(); // Returns the current thread state. | ||||
| private: | private: | ||||
| Mutex MyMutex; // Protect our data with this. | Mutex MyMutex; // Protect our data with this. | ||||
| set<Thread*> KnownThreads; // Keep track of all threads. | |||||
| std::set<Thread*> KnownThreads; // Keep track of all threads. | |||||
| void rememberThread(Thread* T); // Threads register themselves. | void rememberThread(Thread* T); // Threads register themselves. | ||||
| void forgetThread(Thread* T); // Threads remove themselves. | void forgetThread(Thread* T); // Threads remove themselves. | ||||
| // End Thread Manager | // End Thread Manager | ||||
| //////////////////////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////////////////////// | ||||
| //////////////////////////////////////////////////////////////////////////////// | |||||
| // A ProductionQueue is a templated, thread safe mechanism for implementing | |||||
| // a producer/consumer relationship. The objects in the queue should be simple | |||||
| // data so that they can be created, destroyed, and copied without trouble. Put | |||||
| // another way - the objects in the ProductionQueue should be lightweight | |||||
| // handles for other things. Those things should be created and destroyed | |||||
| // elsewhere. | |||||
| template<typename T> // Templatized | |||||
| class ProductionQueue { // Production Queue Class | |||||
| private: | |||||
| Mutex myMutex; // Contains a mutex and | |||||
| volatile unsigned int LatestSize; // a volatile (blinking light) size | |||||
| ProductionGateway myGateway; // integrated with a production | |||||
| queue<T> myQueue; // gateway and a queue. | |||||
| public: | |||||
| ProductionQueue() : LatestSize(0) {} // The size always starts at zero. | |||||
| T take() { // To consume a queued object | |||||
| myGateway.consume(); // we wait on the production gateway | |||||
| ScopeMutex OneAtATimePlease(myMutex); // and when we get through we lock | |||||
| T O = myQueue.front(); // the mutext, take the object on the | |||||
| myQueue.pop(); // front of the queue, pop it out, | |||||
| LatestSize = myQueue.size(); // and rest our size (blinking light). | |||||
| return O; // Then return the object we got. | |||||
| } | |||||
| void give(T O) { // To produce a queued object | |||||
| ScopeMutex OneAtATimePlease(myMutex); // we wait on the mutex. When we | |||||
| myQueue.push(O); // get through we push our object | |||||
| LatestSize = myQueue.size(); // into the queue, reset our size | |||||
| myGateway.produce(); // indicator and tell the gateway. | |||||
| } // When we're done it can be grabbed. | |||||
| unsigned int size() { // To check the size we look at | |||||
| return LatestSize; // the blinking light. | |||||
| } | |||||
| }; | |||||
| // End Production Queue | |||||
| //////////////////////////////////////////////////////////////////////////////// | |||||
| #endif | |||||
| //////////////////////////////////////////////////////////////////////////////// | |||||
| // A ProductionQueue is a templated, thread safe mechanism for implementing | |||||
| // a producer/consumer relationship. The objects in the queue should be simple | |||||
| // data so that they can be created, destroyed, and copied without trouble. Put | |||||
| // another way - the objects in the ProductionQueue should be lightweight | |||||
| // handles for other things. Those things should be created and destroyed | |||||
| // elsewhere. | |||||
| template<typename T> // Templatized | |||||
| class ProductionQueue { // Production Queue Class | |||||
| private: | |||||
| Mutex myMutex; // Contains a mutex and | |||||
| volatile unsigned int LatestSize; // a volatile (blinking light) size | |||||
| ProductionGateway myGateway; // integrated with a production | |||||
| std::queue<T> myQueue; // gateway and a queue. | |||||
| public: | |||||
| ProductionQueue() : LatestSize(0) {} // The size always starts at zero. | |||||
| T take() { // To consume a queued object | |||||
| myGateway.consume(); // we wait on the production gateway | |||||
| ScopeMutex OneAtATimePlease(myMutex); // and when we get through we lock | |||||
| T O = myQueue.front(); // the mutext, take the object on the | |||||
| myQueue.pop(); // front of the queue, pop it out, | |||||
| LatestSize = myQueue.size(); // and rest our size (blinking light). | |||||
| return O; // Then return the object we got. | |||||
| } | |||||
| void give(T O) { // To produce a queued object | |||||
| ScopeMutex OneAtATimePlease(myMutex); // we wait on the mutex. When we | |||||
| myQueue.push(O); // get through we push our object | |||||
| LatestSize = myQueue.size(); // into the queue, reset our size | |||||
| myGateway.produce(); // indicator and tell the gateway. | |||||
| } // When we're done it can be grabbed. | |||||
| unsigned int size() { // To check the size we look at | |||||
| return LatestSize; // the blinking light. | |||||
| } | |||||
| }; | |||||
| // End Production Queue | |||||
| //////////////////////////////////////////////////////////////////////////////// | |||||
| // End Of Include MNR_threading Once Only ====================================== | |||||
| } // End namespace codedweller |
| // timing.cpp | // timing.cpp | ||||
| // | // | ||||
| // Copyright (C) 2006 - 2009 MicroNeil Research Corporation. | |||||
| // Copyright (C) 2004-2020 MicroNeil Research Corporation. | |||||
| // | // | ||||
| // See the corresponding .hpp file for descriptions and history. | |||||
| // | |||||
| // This program is part of the MicroNeil Research Open Library Project. For | |||||
| // more information go to http://www.microneil.com/OpenLibrary/index.html | |||||
| // | |||||
| // This program is free software; you can redistribute it and/or modify it | |||||
| // under the terms of the GNU General Public License as published by the | |||||
| // Free Software Foundation; either version 2 of the License, or (at your | |||||
| // option) any later version. | |||||
| // | |||||
| // This program is distributed in the hope that it will be useful, but WITHOUT | |||||
| // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |||||
| // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |||||
| // more details. | |||||
| // | |||||
| // You should have received a copy of the GNU General Public License along with | |||||
| // this program; if not, write to the Free Software Foundation, Inc., 59 Temple | |||||
| // Place, Suite 330, Boston, MA 02111-1307 USA | |||||
| // This software is released under the MIT license. See LICENSE.TXT. | |||||
| #include <ctime> | #include <ctime> | ||||
| #include <sys/time.h> | #include <sys/time.h> | ||||
| #include "timing.hpp" | #include "timing.hpp" | ||||
| // Introduce the standard namespace //////////////////////////////////////////// | |||||
| using namespace std; | |||||
| namespace codedweller { | |||||
| /////////////////////////////////////////////////////////////////////////////// | /////////////////////////////////////////////////////////////////////////////// | ||||
| // class Sleeper - An object that remembers how long it is supposed to sleep. | // class Sleeper - An object that remembers how long it is supposed to sleep. | ||||
| if(x < MinimumSleeperTime || | if(x < MinimumSleeperTime || | ||||
| x > MaximumSleeperTime) // If it's not a good time value | x > MaximumSleeperTime) // If it's not a good time value | ||||
| throw BadSleeperValue(); // then throw the exception. | throw BadSleeperValue(); // then throw the exception. | ||||
| MillisecondsToSleep = x; // If it is good - set it. | |||||
| MillisecondsToSleep = x; // If it is good - set it. | |||||
| return MillisecondsToSleep; // Return the set value. | return MillisecondsToSleep; // Return the set value. | ||||
| } | } | ||||
| // a natural spiral. | // a natural spiral. | ||||
| /////////////////////////////////////////////////////////////////////////////// | /////////////////////////////////////////////////////////////////////////////// | ||||
| PollTimer::PollTimer(int Nom, int Max) : | |||||
| NominalPollTime(MinimumSleeperTime), | |||||
| PollTimer::PollTimer(int Nom, int Max) : | |||||
| NominalPollTime(MinimumSleeperTime), | |||||
| MaximumPollTime(MinimumSleeperTime) { // Construction requires a | MaximumPollTime(MinimumSleeperTime) { // Construction requires a | ||||
| setNominalPollTime(Nom); // nominal delay to use and | setNominalPollTime(Nom); // nominal delay to use and | ||||
| setMaximumPollTime(Max); // a maximum delay to allow. | setMaximumPollTime(Max); // a maximum delay to allow. | ||||
| bool Timeout::isExpired() { // Return true if time is up. | bool Timeout::isExpired() { // Return true if time is up. | ||||
| return (!(myTimer.getElapsedTime() < myDuration)); // Check the elapsed time against myDuration. | return (!(myTimer.getElapsedTime() < myDuration)); // Check the elapsed time against myDuration. | ||||
| } | } | ||||
| } // End namespace codedweller |
| // timing.hpp | // timing.hpp | ||||
| // | // | ||||
| // Copyright (C) 2004-2009 MicroNeil Research Corporation. | |||||
| // This program is part of the MicroNeil Research Open Library Project. For | |||||
| // more information go to http://www.microneil.com/OpenLibrary/index.html | |||||
| // | |||||
| // This program is free software; you can redistribute it and/or modify it | |||||
| // under the terms of the GNU General Public License as published by the | |||||
| // Free Software Foundation; either version 2 of the License, or (at your | |||||
| // option) any later version. | |||||
| // Copyright (C) 2004-2020 MicroNeil Research Corporation. | |||||
| // | // | ||||
| // This program is distributed in the hope that it will be useful, but WITHOUT | |||||
| // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |||||
| // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |||||
| // more details. | |||||
| // This software is released under the MIT license. See LICENSE.TXT. | |||||
| // | // | ||||
| // You should have received a copy of the GNU General Public License along with | |||||
| // this program; if not, write to the Free Software Foundation, Inc., 59 Temple | |||||
| // Place, Suite 330, Boston, MA 02111-1307 USA | |||||
| // The purpose of this module is to abstract timing functions for | // The purpose of this module is to abstract timing functions for | ||||
| // cross platform C++ development usning GNU compilers in *nix and | // cross platform C++ development usning GNU compilers in *nix and | ||||
| // win32 environments (minGW). Timing resolution is in milliseconds | // win32 environments (minGW). Timing resolution is in milliseconds | ||||
| // throughout to provide consistency and reasonable expectations. | // throughout to provide consistency and reasonable expectations. | ||||
| // 20060404 _M Added Timer::start(msclock startt) for chaining. | |||||
| // 20060403 _M This "timing" module has been completed and tested on | |||||
| // win32 (compiled using CodeBlocks and minGW) and on RHES3 (g++). | |||||
| // | |||||
| // The bottom line is that this code is perfect for most applications that | |||||
| // don't need real-time interaction on the win32 platform. That is, for | |||||
| // any application that can accept 15ms or so of "wiggle" in their timing | |||||
| // functions. On linux I was able to observe very consistent results with | |||||
| // variations measured in 1-2ms. | |||||
| // | |||||
| // Aynone seeking real-time accuracy on the win32 platform will need to contend | |||||
| // with all of the landmines in place against that and will need to write more | |||||
| // ellaborate versions of Timer::getLocalRawClock() and Sleeper::doRawSleep() | |||||
| // aa appropriate for their application. The existing code should work fine for | |||||
| // almost all other applications. | |||||
| // | |||||
| // This code was written with that in mind to some extent. That is why all of | |||||
| // the timing functions are measured in milliseconds rather than microseconds | |||||
| // or something smaller. Milliseconds are convenient for polling delays, | |||||
| // communications timeouts, measuring database application performance, and | |||||
| // other similar tasks. For that purpose - this timing module is just fine :-) | |||||
| // 20060323 _M Rewrote this module from a combination of previous | |||||
| // bits and pieces. This module will provide classes that abstract | |||||
| // timing functions for use in GNU projects on *nix and win32 systems. | |||||
| #ifndef MNR_timing | |||||
| #define MNR_timing | |||||
| // Introduce the standard namespace /////////////////////////////////////////// | |||||
| #pragma once | |||||
| using namespace std; | |||||
| namespace codedweller { | |||||
| /////////////////////////////////////////////////////////////////////////////// | /////////////////////////////////////////////////////////////////////////////// | ||||
| // class Sleeper - An object that remembers how long it is supposed to sleep. | // class Sleeper - An object that remembers how long it is supposed to sleep. | ||||
| private: | private: | ||||
| bool RunningFlag; // True if clock is running. | |||||
| bool RunningFlag; // True if clock is running. | |||||
| msclock StartTime; // TimeOfDay at start. | msclock StartTime; // TimeOfDay at start. | ||||
| msclock StopTime; // TimeOfDay at stop or check. | msclock StopTime; // TimeOfDay at stop or check. | ||||
| ** Returns true if time is up. | ** Returns true if time is up. | ||||
| */ | */ | ||||
| #endif // End MNR_timing once-only switch. | |||||
| } // End namespace codedweller |