Browse Source

no need to strip accumulator twice

master
madscientist 4 years ago
parent
commit
03c3be3be0
20 changed files with 1458 additions and 1667 deletions
  1. 12
    16
      base64codec.cpp
  2. 16
    14
      base64codec.hpp
  3. 603
    63
      configuration.cpp
  4. 87
    108
      configuration.hpp
  5. 0
    576
      configuration.inline.hpp
  6. 30
    33
      faults.hpp
  7. 10
    9
      histogram.hpp
  8. 14
    17
      mangler.cpp
  9. 10
    8
      mangler.hpp
  10. 59
    56
      mishmash.cpp
  11. 9
    5
      mishmash.hpp
  12. 423
    90
      networking.cpp
  13. 53
    68
      networking.hpp
  14. 0
    375
      networking.inline.hpp
  15. 19
    5
      onetimepad.cpp
  16. 8
    6
      onetimepad.hpp
  17. 11
    26
      threading.cpp
  18. 80
    116
      threading.hpp
  19. 8
    25
      timing.cpp
  20. 6
    51
      timing.hpp

+ 12
- 16
base64codec.cpp View File

@@ -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

+ 16
- 14
base64codec.hpp View File

@@ -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
}

+ 603
- 63
configuration.cpp View File

@@ -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

+ 87
- 108
configuration.hpp View File

@@ -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

+ 0
- 576
configuration.inline.hpp View File

@@ -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;
}

+ 30
- 33
faults.hpp View File

@@ -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

+ 10
- 9
histogram.hpp View File

@@ -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


+ 14
- 17
mangler.cpp View File

@@ -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

+ 10
- 8
mangler.hpp View File

@@ -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

+ 59
- 56
mishmash.cpp View File

@@ -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());
}

}

+ 9
- 5
mishmash.hpp View File

@@ -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

+ 423
- 90
networking.cpp View File

@@ -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

+ 53
- 68
networking.hpp View File

@@ -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

+ 0
- 375
networking.inline.hpp View File

@@ -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.
}

+ 19
- 5
onetimepad.cpp View File

@@ -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

+ 8
- 6
onetimepad.hpp View File

@@ -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

+ 11
- 26
threading.cpp View File

@@ -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

+ 80
- 116
threading.hpp View File

@@ -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

+ 8
- 25
timing.cpp View File

@@ -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

+ 6
- 51
timing.hpp View File

@@ -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

Loading…
Cancel
Save