@@ -1,13 +1,12 @@ | |||
// 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" | |||
namespace base64codec { | |||
namespace codedweller { | |||
const static char base64encode[65] = // Base64 encoding characters. | |||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; | |||
@@ -48,10 +47,6 @@ const static unsigned char base64decode[256] = { | |||
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 ///////////////////////////////////////////////////////////////// | |||
void to_base64::convert(const unsigned char* bfr, const int len) { // Converts from a char buffer. | |||
@@ -135,12 +130,12 @@ void to_base64::convert(const unsigned char* bfr, const int len) { | |||
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 ;-) | |||
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 ;-) | |||
convert(reinterpret_cast<const unsigned char*>(&bfr[0]), bfr.size()); // Do this to get it done. | |||
} | |||
@@ -156,7 +151,7 @@ to_base64::to_base64(const char* bfr, const int len) : | |||
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 ;-) | |||
convert(reinterpret_cast<const unsigned char*>(s.c_str()), s.length()); // Do this to get it done. | |||
} | |||
@@ -250,17 +245,17 @@ void from_base64::convert(const unsigned char* bfr, const int len) { | |||
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. | |||
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. | |||
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. | |||
convert(reinterpret_cast<const unsigned char*>(s.c_str()), s.length()); // This is how we do it. | |||
} | |||
@@ -274,3 +269,4 @@ bool from_base64::Bad() { | |||
return BadConversion; | |||
} | |||
} // end namespace codedweller |
@@ -1,17 +1,20 @@ | |||
// 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 <cstring> | |||
#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. | |||
private: | |||
@@ -19,9 +22,9 @@ class to_base64 : public base64buffer { | |||
void convert(const unsigned char* bfr, const int len); // Does the actual work. | |||
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 unsigned char* bfr, const int len); // Converts from a uchar buffer. | |||
to_base64(const char* bfr, const int len); // Converts from a char buffer. | |||
@@ -38,12 +41,11 @@ class from_base64 : public base64buffer { | |||
void convert(const unsigned char* bfr, const int len); // Does the actual work. | |||
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. | |||
bool Bad(); // True if conversion wasn't complete. | |||
}; | |||
#endif | |||
} |
@@ -1,29 +1,568 @@ | |||
// 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" | |||
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 ////////////////////////////////////////////////////////// | |||
@@ -354,7 +893,7 @@ ConfigurationElement::~ConfigurationElement() { | |||
// Delete my 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 | |||
while(iAttribute != myAttributes.end()) { // loop through the whole list. | |||
delete (*iAttribute); // Delete each attribute | |||
@@ -366,7 +905,7 @@ ConfigurationElement::~ConfigurationElement() { | |||
// Delete my sub-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 | |||
while(iElement != myElements.end()) { // loop through the whole list. | |||
delete (*iElement); // Delete each element | |||
@@ -378,7 +917,7 @@ ConfigurationElement::~ConfigurationElement() { | |||
// Delete my 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 | |||
while(iMnemonic != myMnemonics.end()) { // loop through the whole list. | |||
delete (*iMnemonic); // Delete each mnemonic | |||
@@ -390,7 +929,7 @@ ConfigurationElement::~ConfigurationElement() { | |||
// Delete my 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 | |||
while(iTranslator != myTranslators.end()) { // loop through the whole list. | |||
delete (*iTranslator); // Delete each translator | |||
@@ -409,7 +948,7 @@ ConfigurationElement::~ConfigurationElement() { | |||
} | |||
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. | |||
ConfigurationElement* N = new ConfigurationElement( // Create a new Element with the | |||
@@ -422,8 +961,8 @@ ConfigurationElement& ConfigurationElement::Element( | |||
} | |||
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 | |||
Name, // name provided and | |||
@@ -435,7 +974,7 @@ ConfigurationElement& ConfigurationElement::Element( | |||
} | |||
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. | |||
ConfigurationElement* N = new ConfigurationElement( // Create a new Element with the | |||
@@ -448,7 +987,7 @@ ConfigurationElement& ConfigurationElement::Element( | |||
} | |||
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. | |||
ConfigurationElement* N = new ConfigurationElement( // Create a new Element with the | |||
@@ -461,7 +1000,7 @@ ConfigurationElement& ConfigurationElement::Element( | |||
} | |||
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. | |||
ConfigurationElement* N = new ConfigurationElement( // Create a new Element with the | |||
@@ -473,9 +1012,9 @@ ConfigurationElement& ConfigurationElement::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. | |||
@@ -484,7 +1023,7 @@ ConfigurationAttribute& ConfigurationElement::Attribute(const string Name) { | |||
} | |||
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. | |||
myCleanFlag = false; // New attributes make us dirty. | |||
@@ -498,8 +1037,8 @@ ConfigurationAttribute& ConfigurationElement::Attribute( | |||
} | |||
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. | |||
@@ -512,7 +1051,7 @@ ConfigurationAttribute& ConfigurationElement::Attribute( | |||
} | |||
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. | |||
myCleanFlag = false; // New attributes make us dirty. | |||
@@ -526,7 +1065,7 @@ ConfigurationAttribute& ConfigurationElement::Attribute( | |||
} | |||
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. | |||
myCleanFlag = false; // New attributes make us dirty. | |||
@@ -540,7 +1079,7 @@ ConfigurationAttribute& ConfigurationElement::Attribute( | |||
} | |||
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. | |||
myCleanFlag = false; // New attributes make us dirty. | |||
@@ -561,7 +1100,7 @@ ConfigurationElement& ConfigurationElement::mapTo( | |||
} | |||
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 | |||
new StringTranslator(x, init); // with the values i'm given, | |||
myTranslators.push_back(N); // push it onto my list, then | |||
@@ -601,7 +1140,7 @@ void ConfigurationElement::initialize() { | |||
// Initialize the elements below me | |||
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 | |||
while(iElement != myElements.end()) { // loop through the whole list. | |||
(*iElement)->initialize(); // Initialize each element | |||
@@ -616,7 +1155,7 @@ void ConfigurationElement::initialize() { | |||
// Initialize my own 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 | |||
while(iTranslator != myTranslators.end()) { // loop through the whole list. | |||
(*iTranslator)->initialize(); // Initialize each translator | |||
@@ -627,7 +1166,7 @@ void ConfigurationElement::initialize() { | |||
// Initialize my own 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 | |||
while(iAttribute != myAttributes.end()) { // loop through the whole list. | |||
(*iAttribute)->initialize(); // Initialize each attribute | |||
@@ -648,7 +1187,7 @@ void ConfigurationElement::initialize() { | |||
} | |||
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 | |||
while(iConfigurator != myStartConfigurators.end()) { // loop through the whole list. | |||
(** iConfigurator)(*this, D); // Launch each configurator with self. | |||
@@ -657,7 +1196,7 @@ void ConfigurationElement::runStartConfigurators(ConfigurationData& D) { | |||
} | |||
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 | |||
while(iConfigurator != myEndConfigurators.end()) { // loop through the whole list. | |||
(** iConfigurator)(*this, D); // Launch each configurator with self. | |||
@@ -744,7 +1283,7 @@ bool ConfigurationElement::interpret(ConfigurationData& Data) { | |||
if(isalpha(Data.Data(Index))) { // If it looks like an attribute... | |||
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 | |||
while(iAttribute != myAttributes.end()) { // loop through the whole list. | |||
ParseHappened = (* iAttribute)->interpret(Data); // Have each attribute interpret(Data) | |||
@@ -848,7 +1387,7 @@ bool ConfigurationElement::interpret(ConfigurationData& Data) { | |||
NewLines = 0; // Reset our new lines count. | |||
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 | |||
while(iElement != myElements.end()) { // loop through the whole list. | |||
ConfigurationElement& doNode = **iElement; // Grab the element we're on. | |||
@@ -906,7 +1445,7 @@ bool ConfigurationElement::interpret(ConfigurationData& Data) { | |||
// Create the Content buffer... | |||
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]; | |||
copyDataCountLines(Bfr, Data, Startdex, Stopdex); // Get our data and ignore our lines. | |||
@@ -918,7 +1457,7 @@ bool ConfigurationElement::interpret(ConfigurationData& Data) { | |||
// Translate our data by Mnemonic | |||
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 | |||
while(iMnemonic != myMnemonics.end()) { // loop through the whole list. | |||
if(true == ((*iMnemonic)->test(TranslationData))) { // Check to see if the mnemonic matches. | |||
@@ -933,7 +1472,7 @@ bool ConfigurationElement::interpret(ConfigurationData& Data) { | |||
// 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 | |||
while(iTranslator != myTranslators.end()) { // loop through the whole list. | |||
(*iTranslator)->translate(TranslationData); // Pass the data to each one then | |||
@@ -954,7 +1493,7 @@ ConfigurationAttribute::~ConfigurationAttribute() { | |||
// Delete my 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 | |||
while(iMnemonic != myMnemonics.end()) { // loop through the whole list. | |||
delete (*iMnemonic); // Delete each mnemonic | |||
@@ -966,7 +1505,7 @@ ConfigurationAttribute::~ConfigurationAttribute() { | |||
// Delete my 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 | |||
while(iTranslator != myTranslators.end()) { // loop through the whole list. | |||
delete (*iTranslator); // Delete each translator | |||
@@ -990,7 +1529,7 @@ ConfigurationAttribute& ConfigurationAttribute::mapTo( | |||
} | |||
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 | |||
new StringTranslator(x, init); // with the values i'm given, | |||
myTranslators.push_back(N); // push it onto my list, then | |||
@@ -1028,7 +1567,7 @@ ConfigurationAttribute& ConfigurationAttribute::mapTo( | |||
void ConfigurationAttribute::initialize() { // Reset all translators to defaults. | |||
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 | |||
while(iTranslator != myTranslators.end()) { // loop through the whole list. | |||
(*iTranslator)->initialize(); // initialize each translator | |||
@@ -1099,7 +1638,7 @@ bool ConfigurationAttribute::interpret(ConfigurationData& Data) { | |||
// Read our data. | |||
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]; | |||
NewLines += copyDataCountLines(Bfr, Data, Startdex, Stopdex); // Get our data and count our lines. | |||
@@ -1111,7 +1650,7 @@ bool ConfigurationAttribute::interpret(ConfigurationData& Data) { | |||
// Translate our data by Mnemonic | |||
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 | |||
while(iMnemonic != myMnemonics.end()) { // loop through the whole list. | |||
if(true == ((*iMnemonic)->test(TranslationData))){ // Check to see if the mnemonic matches. | |||
@@ -1127,7 +1666,7 @@ bool ConfigurationAttribute::interpret(ConfigurationData& Data) { | |||
// Put our TranslationData through each Translator. | |||
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 | |||
while(iTranslator != myTranslators.end()) { // loop through the whole list. | |||
(*iTranslator)->translate(TranslationData); // Pass the data to each one and | |||
@@ -1173,11 +1712,11 @@ ConfigurationData::ConfigurationData(const char* FileName) : | |||
myIndex(0), // Our Index is zero | |||
myLine(1) { // We start on line 1 | |||
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. | |||
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. | |||
if(CFGFile.bad()) { // If the read failed, we're unusable! | |||
delete[] myDataBuffer; // Delete the buffer | |||
@@ -1194,17 +1733,17 @@ ConfigurationData::ConfigurationData(const char* FileName) : | |||
} // 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. | |||
myBufferSize(0), // No length yet. | |||
myIndex(0), // Our Index is zero | |||
myLine(1) { // We start on line 1 | |||
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. | |||
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. | |||
if(CFGFile.bad()) { // If the read failed, we're unusable! | |||
delete[] myDataBuffer; // Delete the buffer | |||
@@ -1250,3 +1789,4 @@ void ConfiguratorSetTrueOnComplete::operator()( | |||
} // true. | |||
} | |||
} // End namespace codedweller |
@@ -1,28 +1,15 @@ | |||
// 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 ============================================================= | |||
// The configuration module provides a platform for reading configuration files | |||
// (or string data) containing well-formed xml and mapping that data to program | |||
// variables. | |||
// | |||
// The idea is to provide the ability for an object or application to provide | |||
// a modular "configuration" object that models a hierarchical collection of | |||
// "settings" that can be represented easily in code and in xml. | |||
@@ -105,8 +92,7 @@ | |||
// Include This Header Once Only =============================================== | |||
#ifndef configuration_included | |||
#define configuration_included | |||
#pragma once | |||
#include <string> | |||
#include <vector> | |||
@@ -116,7 +102,7 @@ | |||
#include <cstdlib> | |||
#include <list> | |||
using namespace std; | |||
namespace codedweller { | |||
class ConfigurationElement; // Elements exist | |||
class ConfigurationAttribute; // Attributes exist | |||
@@ -135,21 +121,21 @@ class ConfigurationElement { | |||
private: | |||
string myName; // Elements have a name. | |||
std::string myName; // Elements have a name. | |||
// External important things I remember but don't touch... | |||
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... | |||
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... | |||
@@ -167,10 +153,10 @@ class ConfigurationElement { | |||
public: | |||
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 string Name, ConfigurationElement& Parent); // parrent. | |||
ConfigurationElement(const std::string Name, ConfigurationElement& Parent); // parrent. | |||
// Upon desctruction an element will delete all subordinate objects: | |||
// * All sub element objects. | |||
@@ -189,7 +175,7 @@ class ConfigurationElement { | |||
// 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(ConfigurationElement& newParent); // Set the parent of this element. | |||
@@ -203,7 +189,7 @@ class ConfigurationElement { | |||
// 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 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. | |||
//// Root-Node elements are _usually_ empty and without attributes in xml | |||
@@ -217,7 +203,7 @@ class ConfigurationElement { | |||
ConfigurationElement& Element( // Mapping factory for convenience, | |||
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, | |||
const char* Name, // requires a name, of course, | |||
@@ -234,23 +220,23 @@ class ConfigurationElement { | |||
// string versions | |||
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. | |||
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, | |||
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. | |||
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. | |||
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. | |||
// End methods for heading back up the tree at the end of an element. | |||
@@ -259,12 +245,12 @@ class ConfigurationElement { | |||
ConfigurationElement& End(); // Return this element's 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. | |||
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. | |||
@@ -276,7 +262,7 @@ class ConfigurationElement { | |||
ConfigurationAttribute& Attribute( // Mapping factory for convenience, | |||
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, | |||
const char* Name, // requires a name, of course, | |||
@@ -293,23 +279,23 @@ class ConfigurationElement { | |||
// string versions | |||
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. | |||
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, | |||
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. | |||
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. | |||
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. | |||
// Elements can Initialize() at each Interpret() call. | |||
@@ -330,21 +316,21 @@ class ConfigurationElement { | |||
// converts it into the expected type, and sets one or more variables | |||
// to the converted value. Usually - just one variable. | |||
ConfigurationElement& mapTo(ConfigurationTranslator& newTranslator); // Add a Translator to this element. | |||
ConfigurationElement& mapTo(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 | |||
// configuration easier to understand and less error prone. When the | |||
// contents match a mnemnoic then the translation of the mnemonic is | |||
// passed to the Translators instead of the raw contents. | |||
ConfigurationElement& Mnemonic(const char* name, const char* value); // Add a mnemonic using c strings. | |||
ConfigurationElement& Mnemonic(const char* name, const 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 | |||
// recursively. The data is loaded into a ConfigurationData object which | |||
@@ -388,11 +374,11 @@ class ConfigurationAttribute { | |||
private: | |||
string myName; // Elements have a name. | |||
std::string myName; // Elements have a name. | |||
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 myIndex; // Last char position I was seen on. | |||
@@ -400,8 +386,8 @@ class ConfigurationAttribute { | |||
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. | |||
// See Elements for similar warnings about objects provided to | |||
@@ -412,7 +398,7 @@ class ConfigurationAttribute { | |||
// 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. | |||
int Line(); // Get the last line number. | |||
int Index(); // Get the last data position. | |||
@@ -428,7 +414,7 @@ class ConfigurationAttribute { | |||
//// 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 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. | |||
//// Root-Node elements are _usually_ empty and without attributes in xml | |||
@@ -442,7 +428,7 @@ class ConfigurationAttribute { | |||
ConfigurationElement& Element( // Mapping factory for convenience, | |||
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, | |||
const char* Name, // requires a name, of course, | |||
@@ -459,35 +445,35 @@ class ConfigurationAttribute { | |||
// string versions | |||
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. | |||
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, | |||
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. | |||
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. | |||
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. | |||
// End methods for heading back up the tree at the end of an element. | |||
ConfigurationElement& End(); // Return this element's parent. | |||
ConfigurationElement& End(const char* Name); // Check the name and return the parent | |||
ConfigurationElement& End(const 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. | |||
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. | |||
@@ -499,7 +485,7 @@ class ConfigurationAttribute { | |||
ConfigurationAttribute& Attribute( // Mapping factory for convenience, | |||
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, | |||
const char* Name, // requires a name, of course, | |||
@@ -516,23 +502,23 @@ class ConfigurationAttribute { | |||
// string versions | |||
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. | |||
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, | |||
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. | |||
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. | |||
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. | |||
//// Set Init On Interprete for the parent element. | |||
@@ -549,18 +535,18 @@ class ConfigurationAttribute { | |||
// apply to the parent element's contents. Here they are for use on this | |||
// attribute. | |||
ConfigurationAttribute& mapTo(ConfigurationTranslator& newTranslator); // Add a Translator to this attribute. | |||
ConfigurationAttribute& mapTo(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. | |||
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. | |||
@@ -588,7 +574,7 @@ class ConfigurationData { | |||
public: | |||
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(); // Destroys the internal buffer etc. | |||
@@ -599,7 +585,7 @@ class ConfigurationData { | |||
int Line(); // Reads the current Line number. | |||
int addNewLines(int Count); // Increments the Line number. | |||
stringstream Log; // Convenient Interpret log. | |||
std::stringstream Log; // Convenient Interpret log. | |||
}; | |||
@@ -610,7 +596,7 @@ class ConfigurationData { | |||
// collection of the basic translators used for built-in mapTo()s. | |||
class ConfigurationTranslator { // Translators exist | |||
public: | |||
public: | |||
virtual ~ConfigurationTranslator(){}; // Stop No Virt Dtor warnings. | |||
virtual void translate(const char* Value) = 0; // Pure virtual translator. | |||
virtual void initialize() = 0; // Pure virtual initializer. | |||
@@ -618,13 +604,13 @@ class ConfigurationTranslator { | |||
class StringTranslator : public ConfigurationTranslator { | |||
private: | |||
string& myVariable; // Variable to map. | |||
string myInitializer; // Initial/Default value. | |||
std::string& myVariable; // Variable to map. | |||
std::string myInitializer; // Initial/Default value. | |||
public: | |||
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 initialize(); // Provide an initialization method. | |||
@@ -685,13 +671,13 @@ class BoolTranslator : public ConfigurationTranslator { | |||
class ConfigurationMnemonic { // Mnemonics | |||
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: | |||
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 ////////////////////////////////////////////////////////////// | |||
@@ -707,14 +693,10 @@ class ConfigurationMnemonic { | |||
class Configurator { // Configurators exist | |||
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. | |||
}; | |||
//// Include our inline methods //////////////////////////////////////////////// | |||
#include "configuration.inline.hpp" | |||
//// Utilities ///////////////////////////////////////////////////////////////// | |||
// SetTrueOnComplete Configurator ////////////////////////////////////////////// | |||
@@ -729,7 +711,4 @@ class ConfiguratorSetTrueOnComplete : public Configurator { | |||
void operator()(ConfigurationElement& E, ConfigurationData& D); // Handle the operation. | |||
}; | |||
#endif | |||
// End Of Include Only Once | |||
} // End namespace codedweller |
@@ -1,576 +0,0 @@ | |||
// 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; | |||
} |
@@ -1,8 +1,8 @@ | |||
// 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 | |||
// unreasonable or necessary conditions in our code. They are constructed with | |||
@@ -18,15 +18,14 @@ | |||
// 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(). | |||
#ifndef MNR_faults | |||
#define MNR_faults | |||
#pragma once | |||
#include <stdexcept> | |||
#include <cstdlib> | |||
#include <iostream> | |||
#include <string> | |||
using namespace std; | |||
namespace codedweller { | |||
const int DefaultExitCode = EXIT_FAILURE; // Use this when no code is provided. | |||
@@ -34,62 +33,62 @@ class AbortCheck { | |||
private: | |||
const string myDescription; // This is what I have to say. | |||
const std::string myDescription; // This is what I have to say. | |||
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) | |||
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. | |||
} | |||
} | |||
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. | |||
private: | |||
const string myDescription; // This is what I have to say. | |||
const std::string myDescription; // This is what I have to say. | |||
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) | |||
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. | |||
} | |||
} | |||
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. | |||
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(). | |||
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. | |||
void operator()(bool X) const { // Apply me like assert(exp) | |||
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. | |||
} | |||
} | |||
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. | |||
}; | |||
@@ -97,30 +96,30 @@ class ExitFault { | |||
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(). | |||
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. | |||
void operator()(bool X) const { // Apply me like assert(! exp) | |||
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. | |||
} | |||
} | |||
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. | |||
}; | |||
class RuntimeCheck : public runtime_error { // Throw if this check fails. | |||
class RuntimeCheck : public std::runtime_error { // Throw if this check fails. | |||
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) | |||
if(false == X) { // If the expression is false then we | |||
@@ -129,11 +128,11 @@ class RuntimeCheck : public runtime_error { | |||
} | |||
}; | |||
class RuntimeFault : public runtime_error { // Throw if we find this fault. | |||
class RuntimeFault : public std::runtime_error { // Throw if we find this fault. | |||
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) | |||
if(true == X) { // If the expression is true then we | |||
@@ -142,11 +141,11 @@ class RuntimeFault : public runtime_error { | |||
} | |||
}; | |||
class LogicCheck : public logic_error { // Throw if this check fails. | |||
class LogicCheck : public std::logic_error { // Throw if this check fails. | |||
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) | |||
if(false == X) { // If the expression is false then we | |||
@@ -155,11 +154,11 @@ class LogicCheck : public logic_error { | |||
} | |||
}; | |||
class LogicFault : public logic_error { // Throw if we find this fault. | |||
class LogicFault : public std::logic_error { // Throw if we find this fault. | |||
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) | |||
if(true == X) { // If the expression is true then we | |||
@@ -168,6 +167,4 @@ class LogicFault : public logic_error { | |||
} | |||
}; | |||
#endif | |||
// End Of Include MNR_faults Once Only ========================================= | |||
} // End namespace codedweller |
@@ -1,13 +1,14 @@ | |||
// 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> | |||
using namespace std; | |||
namespace codedweller { | |||
/** The Histogram class is managed set of HistogramRecords. | |||
*** We play some naughty tricks with pointers to break the rules and | |||
@@ -21,7 +22,7 @@ using namespace std; | |||
class HistogramRecord { // A record to assocate a key and count. | |||
public: | |||
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. | |||
Key(NewKey), Count(0) {} // and a new one starts at count 0. | |||
@@ -30,7 +31,7 @@ class HistogramRecord { | |||
} | |||
}; | |||
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... | |||
int HitCount; | |||
public: | |||
@@ -39,7 +40,7 @@ class Histogram : public set<HistogramRecord> { | |||
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. | |||
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. | |||
int* C; // Play naughty pointer games to access | |||
C = const_cast<int*>(&((*iE).Count)); // the Count for this record inside the | |||
@@ -56,5 +57,5 @@ class Histogram : public set<HistogramRecord> { | |||
} | |||
}; | |||
#endif | |||
} // End namespace codedweller | |||
@@ -1,24 +1,21 @@ | |||
// 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 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. | |||
// Using new optimized chaos driver for uniformity experiments. | |||
// Important in this experiment is proof of highest possible entropy. | |||
#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 | |||
} // value. | |||
@@ -30,7 +27,7 @@ unsigned char MANGLER::ChaosDriver(void) { // Return the current | |||
// value of Position and determining the final output value and the Position | |||
// 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 ( | |||
(i & 0x80)? // This operation is | |||
(i<<1)+1: // described without | |||
@@ -38,7 +35,7 @@ unsigned char MANGLER::Rotate(unsigned char i) { // Bitwise rotates i | |||
); | |||
} | |||
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. | |||
@@ -84,23 +81,23 @@ void MANGLER::ChaosDriver(unsigned char i) { // Drives chaos engine. | |||
// same state with the same fill data characteristics or else the two | |||
// 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 | |||
ChaosDriver(g); // chaos engine and use it | |||
return g; // to moduleate the input. | |||
} // Then drive the engine | |||
// 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 | |||
ChaosDriver(i); // chaos engine and use it | |||
return g; // to demodulate the input. | |||
} // then drive the engine | |||
// 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 | |||
Fill[c]=(unsigned char) c; // value and Position to 0. | |||
} | |||
} // End namespace codedweller |
@@ -1,17 +1,20 @@ | |||
// 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 2 of Mangler Encryption Algorythm, 1998. | |||
// | |||
// 20020119 _M Mangler V3. | |||
// 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: | |||
unsigned char Fill[256]; // Where to store the fill. | |||
@@ -27,8 +30,7 @@ class MANGLER { | |||
unsigned char Encrypt(unsigned char i); // Returns encrypted data. | |||
unsigned char Decrypt(unsigned char i); // Returns decrypted data. | |||
MANGLER(void); // Default. | |||
Mangler(void); // Default. | |||
}; | |||
#endif | |||
} // End namespace codedweller |
@@ -1,71 +1,74 @@ | |||
// 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" | |||
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()); | |||
} | |||
} |
@@ -1,5 +1,9 @@ | |||
// 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 | |||
#include <string> | |||
@@ -7,8 +11,8 @@ | |||
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 |
@@ -1,30 +1,361 @@ | |||
// 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" | |||
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 /////////////////////////////////////////////////// | |||
@@ -37,8 +368,8 @@ WSADATA WSSTartData; | |||
// 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. | |||
case WSA_INVALID_HANDLE: s = "WSA_INVALID_HANDLE"; break; | |||
@@ -146,7 +477,7 @@ string Networking::DescriptiveError(string Msg, int Errno) { | |||
Msg.append(s); // then append it. | |||
} | |||
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. | |||
Msg.append(ErrNoMsg.str()); | |||
} | |||
@@ -181,7 +512,7 @@ Networking::~Networking() { | |||
// 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)); | |||
return Msg; | |||
}; | |||
@@ -232,13 +563,13 @@ IP4Address::operator unsigned long int() const { | |||
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. | |||
memset(stringbfr, 0, sizeof(stringbfr)); // Null out it's space. | |||
int a0, a1, a2, a3; // Grab some integers. | |||
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. | |||
return string(stringbfr); // Return a string. | |||
return std::string(stringbfr); // Return a string. | |||
} | |||
//// SocketAddress methods ///////////////////////////////////////////////////// | |||
@@ -340,7 +671,7 @@ void TCPListener::open() { | |||
if(!OpenStage2Complete) { // Do this stage only once. | |||
int result = // Bind our socket to the LocalAddress. | |||
::bind( | |||
bind( | |||
Handle, | |||
LocalAddress.getPtr_sockaddr(), | |||
LocalAddress.getAddressSize()); | |||
@@ -393,30 +724,30 @@ TCPClient* TCPListener::acceptClient() { | |||
return NULL; // non blocking mode so we return | |||
} // 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. | |||
@@ -433,14 +764,14 @@ int TCPClient::transmit(const char* bfr, int size) { | |||
if(0 > size) // Watch out for bad sizes. | |||
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. | |||
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(Network.WouldBlock(LastError)) { // If the error was "Would Block" then | |||
return NoBytesSent; // return no bytes sent (try again). | |||
@@ -450,7 +781,7 @@ int TCPClient::transmit(const char* bfr, int size) { | |||
"TCPClient::transmit().send()", LastError)); | |||
} | |||
} | |||
return ByteCount; // Usually: return the sent byte count. | |||
} | |||
@@ -544,12 +875,12 @@ void TCPHost::open() { | |||
LastError = 0; // Clear our LastError value. | |||
bool SuccessFlag = true; // Begin optimistically. | |||
// Set Socket Options | |||
// Set Socket Options | |||
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 result = // Set SO_REUSEADDR before bind(). | |||
setsockopt( | |||
@@ -566,31 +897,31 @@ void TCPHost::open() { | |||
Network.DescriptiveError( | |||
"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. | |||
} // Done with stage 1. | |||
@@ -684,3 +1015,5 @@ int TCPHost::delimited_receive(char* bfr, int size, char delimiter) { | |||
// End Platform Agnostic Stuff | |||
//////////////////////////////////////////////////////////////////////////////// | |||
} // End namespace codedweller |
@@ -1,32 +1,13 @@ | |||
// 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 | |||
// 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 <iostream> | |||
@@ -34,8 +15,6 @@ | |||
#include <sstream> | |||
#include <cstring> | |||
using namespace std; | |||
#include <cstdlib> | |||
#include <cstdio> | |||
#include <cerrno> | |||
@@ -47,9 +26,14 @@ using namespace std; | |||
//// Windows headers... | |||
#include <winsock2.h> | |||
namespace codedweller { | |||
typedef int socklen_t; // Posix uses socklen_t so we mimic it. | |||
typedef SOCKET hSocket; // Winx handles Socket is opaque. | |||
} // End namespace codedweller | |||
#else | |||
//// GNU Headers... | |||
@@ -62,21 +46,27 @@ typedef SOCKET hSocket; | |||
#include <unistd.h> | |||
#include <fcntl.h> | |||
namespace codedweller { | |||
typedef int hSocket; // *nix uses int to handle a 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 | |||
//// 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 ////////////////////////////////////////////////////// | |||
const unsigned long LOCALHOST = 0x7F000001; // 127.0.0.1 as an integer. | |||
@@ -103,14 +93,14 @@ class IP4Address { | |||
IP4Address(const IP4Address&); // Constructor given an IP4Address | |||
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 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 string() const; | |||
operator std::string() const; | |||
bool operator<(const IP4Address Right) const; // < Comparison. | |||
bool operator>(const IP4Address Right) const; // > Comparison. | |||
@@ -151,41 +141,41 @@ class Networking { | |||
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(); | |||
@@ -531,9 +521,4 @@ class UDPBroadcaster : public Socket, public MessagePort { | |||
// End of UDPBroadcaster class | |||
//////////////////////////////////////////////////////////////////////////////// | |||
//// Include Inline methods and functions... | |||
#include "networking.inline.hpp" | |||
#endif | |||
// End include Networking.hpp only once... | |||
} // End namespace codedweller |
@@ -1,375 +0,0 @@ | |||
// 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. | |||
} |
@@ -1,5 +1,8 @@ | |||
// 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 "timing.hpp" | |||
@@ -29,6 +32,8 @@ class OneTimePad { | |||
#include <windows.h> | |||
#include <wincrypt.h> | |||
namespace codedweller { | |||
PadBuffer OneTimePad::Entropy(int Length) { // Get a PadBuffer full of randomness. | |||
PadBuffer Buffer(Length, 0); // Start by initializing the buffer. | |||
HCRYPTPROV provider = 0; // We will need a handle for the source. | |||
@@ -57,16 +62,20 @@ PadBuffer OneTimePad::Entropy(int Length) { | |||
return Buffer; // Return the data we got. | |||
} | |||
} // End namespace codddweller | |||
#else | |||
//// *NIX Strong Entropy Source == /dev/urandom //////////////////////////////// | |||
#include <fstream> | |||
namespace codedweller { | |||
PadBuffer OneTimePad::Entropy(int Length) { // Get Length bytes of strong entropy. | |||
PadBuffer Buffer(Length, 0); // Initialize a buffer to hold them. | |||
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. | |||
if(!Source.bad() && Source.gcount() == Length) { // If we got what we came for then | |||
StrongEntropyFlag = true; // we have strong cryptography. | |||
@@ -82,11 +91,15 @@ PadBuffer OneTimePad::Entropy(int Length) { | |||
return Buffer; // Return the buffer. | |||
} | |||
} // End namespace codedweller | |||
#endif | |||
// End Platform Specific Bits | |||
//////////////////////////////////////////////////////////////////////////////// | |||
namespace codedweller { | |||
// 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 | |||
// milliseconds, the number and times of calls to addLightweightEntropy(), and | |||
@@ -105,7 +118,7 @@ void OneTimePad::addLightweightEntropy() { | |||
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* 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 | |||
PadGenerator.Encrypt( // the results and using one extra | |||
PadGenerator.Encrypt(PrimerBuffer[i])); // round per byte to increase the | |||
@@ -114,7 +127,7 @@ void OneTimePad::addLightweightEntropy() { | |||
void OneTimePad::addEntropy() { // Add strong entropy if available. | |||
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(Fill.at(i))); // round per byte to increase the | |||
} // amount of guessing an attacker | |||
@@ -122,7 +135,7 @@ void OneTimePad::addEntropy() { | |||
void OneTimePad::addEntropy(PadBuffer Entropy) { // Add entropy from a given source. | |||
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.at(i))); // extra round per byte to increase | |||
} // the amount of guessing an attacker | |||
@@ -155,3 +168,4 @@ OneTimePad::OneTimePad() { | |||
} // initial Mangler state. | |||
} // The OneTimePad object is ready. | |||
} // End namespace codedweller |
@@ -1,5 +1,8 @@ | |||
// 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 | |||
// cryptographically strong one-time pads and random numbers upon request. | |||
@@ -10,15 +13,14 @@ | |||
// started. Additional entropy can be provided by the application or again from | |||
// one of the core entropy generators (/dev/urandom or CryptGenRandom). | |||
#ifndef onetimepad_included | |||
#define onetimepad_included | |||
#pragma once | |||
#include <vector> | |||
#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. | |||
private: | |||
@@ -47,4 +49,4 @@ class OneTimePad { | |||
}; | |||
#endif | |||
} // End namespace codedweller |
@@ -1,29 +1,12 @@ | |||
// 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" | |||
using namespace std; // Introduce std namespace. | |||
namespace codedweller { | |||
ThreadManager Threads; // Master thread manager. | |||
@@ -41,7 +24,7 @@ ThreadStatusReport ThreadManager::StatusReport() { | |||
ScopeMutex ThereCanBeOnlyOne(MyMutex); // Protect our set -- a moment in time. | |||
ThreadStatusReport Answer; // Create our vector to hold the report. | |||
for( // Loop through all of the Threads. | |||
set<Thread*>::iterator iT = KnownThreads.begin(); | |||
std::set<Thread*>::iterator iT = KnownThreads.begin(); | |||
iT != KnownThreads.end(); iT++ | |||
) { // Grab each Threads' report. | |||
Thread& X = *(*iT); // Handy reference to the Thread. | |||
@@ -110,8 +93,8 @@ bool Thread::isRunning() { return RunningFlag; } | |||
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 ThreadState& Thread::MyState() { return (*MyThreadState); } // Thread state for this instance. | |||
@@ -143,7 +126,7 @@ void Thread::launchTask() { | |||
CurrentThreadState(ThreadStarted); // Set the running state. | |||
myTask(); // myTask() is called. | |||
} // 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 | |||
BadWhat = e.what(); // we have an idea what went wrong. | |||
} // We shouldn't get other kinds of | |||
@@ -182,7 +165,7 @@ Thread::Thread() : | |||
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. | |||
MyThreadName(N), // Use a generic Thread Name. | |||
MyThread(NULL), // Null the thread handle. | |||
@@ -228,7 +211,7 @@ Thread::Thread() : | |||
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. | |||
MyThreadName(N), // Use a generic Thread Name. | |||
RunningFlag(false), // Can't be running yet. | |||
@@ -470,3 +453,5 @@ void ProductionGateway::consume() { | |||
// End Production Gateway | |||
//////////////////////////////////////////////////////////////////////////////// | |||
} // End namespace codedweller |
@@ -1,23 +1,8 @@ | |||
// 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 differences between posix compatible systems and win32 based systems are | |||
@@ -28,46 +13,15 @@ | |||
// here are designed to cover all of the basics efficiently while hiding the | |||
// 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 <vector> | |||
#include <string> | |||
#include <queue> | |||
#include "faults.hpp" | |||
#include <queue> | |||
#include "faults.hpp" | |||
using namespace std; | |||
namespace codedweller { | |||
class ThreadManager; // ThreadManager does exist. | |||
extern ThreadManager Threads; // Master thread manager. | |||
@@ -82,8 +36,8 @@ extern ThreadManager Threads; | |||
class ThreadState { // Thread State Object. | |||
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 | |||
@@ -91,8 +45,8 @@ class ThreadState { | |||
class ThreadType { | |||
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. | |||
@@ -102,10 +56,10 @@ class ThreadStatusRecord { | |||
Thread* Pointer; // A pointer to the thread. | |||
ThreadType* Type; // A descriptor of it's type. | |||
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 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: | |||
ThreadStatusRecord( // Initialize all items. | |||
@@ -114,13 +68,13 @@ class ThreadStatusRecord { | |||
ThreadState& S, | |||
bool R, | |||
bool B, | |||
string F, | |||
string N | |||
std::string F, | |||
std::string N | |||
) : | |||
Pointer(P), | |||
Type(&T), | |||
State(&S), | |||
Name(N), | |||
Name(N), | |||
isRunning(R), | |||
isBad(B), | |||
Fault(F) | |||
@@ -133,7 +87,7 @@ class ThreadStatusRecord { | |||
isRunning = Right.isRunning; | |||
isBad = Right.isBad; | |||
Fault = Right.Fault; | |||
Name = Right.Name; | |||
Name = Right.Name; | |||
return *this; | |||
} | |||
@@ -148,15 +102,17 @@ class ThreadStatusRecord { | |||
const ThreadState& getState() { return *State; } | |||
bool getRunning() { return isRunning; } | |||
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 namespace codedweller | |||
//////////////////////////////////////////////////////////////////////////////// | |||
// Win32 / POSIX abstractions | |||
@@ -168,6 +124,8 @@ typedef vector<ThreadStatusRecord> ThreadStatusReport; | |||
#include <windows.h> | |||
#include <process.h> | |||
namespace codedweller { | |||
typedef HANDLE thread_primative; // The WIN32 thread primative abstracts | |||
// HANDLE | |||
@@ -178,6 +136,8 @@ inline void threading_yield() { | |||
SwitchToThread(); // we call SwitchToThread(); | |||
} | |||
} // End namespace codedweller | |||
#else | |||
// When in POSIX land... | |||
@@ -186,6 +146,8 @@ inline void threading_yield() { | |||
#include <pthread.h> | |||
#include <sched.h> | |||
namespace codedweller { | |||
typedef pthread_t thread_primative; // The POSIX thread primative abstracts | |||
// pthread_t | |||
@@ -196,11 +158,15 @@ inline void threading_yield() { | |||
sched_yield(); // we call sched_yield(); | |||
} | |||
} // End namespace codedweller | |||
#endif | |||
// End Win32 / POSIX abstractions | |||
//////////////////////////////////////////////////////////////////////////////// | |||
namespace codedweller { | |||
//////////////////////////////////////////////////////////////////////////////// | |||
// 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 | |||
@@ -218,18 +184,18 @@ class Thread { | |||
protected: | |||
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. | |||
bool RunningFlag; // True when thread is in myTask() | |||
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. | |||
public: | |||
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) | |||
void run(); // Method to launch this thread. | |||
@@ -242,9 +208,9 @@ class Thread { | |||
bool isRunning(); // Return the Running 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 ThreadState& MyState(); // Returns the current thread state. | |||
const ThreadState& CurrentThreadState(); // Returns the current thread state. | |||
@@ -406,7 +372,7 @@ class ThreadManager { | |||
private: | |||
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 forgetThread(Thread* T); // Threads remove themselves. | |||
@@ -436,50 +402,48 @@ class ScopeThreadLock { | |||
// 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 |
@@ -1,25 +1,8 @@ | |||
// 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 <sys/time.h> | |||
@@ -33,9 +16,7 @@ | |||
#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. | |||
@@ -92,7 +73,7 @@ int Sleeper::setMillisecondsToSleep(int x) { | |||
if(x < MinimumSleeperTime || | |||
x > MaximumSleeperTime) // If it's not a good time value | |||
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. | |||
} | |||
@@ -129,8 +110,8 @@ void Sleeper::operator()() { | |||
// a natural spiral. | |||
/////////////////////////////////////////////////////////////////////////////// | |||
PollTimer::PollTimer(int Nom, int Max) : | |||
NominalPollTime(MinimumSleeperTime), | |||
PollTimer::PollTimer(int Nom, int Max) : | |||
NominalPollTime(MinimumSleeperTime), | |||
MaximumPollTime(MinimumSleeperTime) { // Construction requires a | |||
setNominalPollTime(Nom); // nominal delay to use and | |||
setMaximumPollTime(Max); // a maximum delay to allow. | |||
@@ -326,3 +307,5 @@ msclock Timeout::getRemainingTime() { | |||
bool Timeout::isExpired() { // Return true if time is up. | |||
return (!(myTimer.getElapsedTime() < myDuration)); // Check the elapsed time against myDuration. | |||
} | |||
} // End namespace codedweller |
@@ -1,62 +1,17 @@ | |||
// 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 | |||
// cross platform C++ development usning GNU compilers in *nix and | |||
// win32 environments (minGW). Timing resolution is in milliseconds | |||
// 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. | |||
@@ -206,7 +161,7 @@ class Timer { | |||
private: | |||
bool RunningFlag; // True if clock is running. | |||
bool RunningFlag; // True if clock is running. | |||
msclock StartTime; // TimeOfDay at start. | |||
msclock StopTime; // TimeOfDay at stop or check. | |||
@@ -357,4 +312,4 @@ class Timeout { | |||
** Returns true if time is up. | |||
*/ | |||
#endif // End MNR_timing once-only switch. | |||
} // End namespace codedweller |