浏览代码

no need to strip accumulator twice

master
madscientist 5 年前
父节点
当前提交
03c3be3be0
共有 20 个文件被更改,包括 1458 次插入1667 次删除
  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 查看文件

// base64codec.cpp // base64codec.cpp
// Copyright (C) 2006 - 2009 MicroNeil Research Corporation
// See base64codec.hpp

//typedef vector<char> base64codec_buffer;
//typedef vector<char>::iterator base64codec_iterator;
//
// Copyright (C) 2004-2020 MicroNeil Research Corporation.
//
// This software is released under the MIT license. See LICENSE.TXT.


#include "base64codec.hpp" #include "base64codec.hpp"


namespace base64codec {
namespace codedweller {


const static char base64encode[65] = // Base64 encoding characters. const static char base64encode[65] = // Base64 encoding characters.
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX // F XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX // F
}; };


} // End namespace base64codec

using namespace base64codec;

//// to_base64 ///////////////////////////////////////////////////////////////// //// to_base64 /////////////////////////////////////////////////////////////////


void to_base64::convert(const unsigned char* bfr, const int len) { // Converts from a char buffer. void to_base64::convert(const unsigned char* bfr, const int len) { // Converts from a char buffer.
BadConversion = false; // If we get here we've done good. BadConversion = false; // If we get here we've done good.
} }


to_base64::to_base64(const vector<unsigned char>& bfr) : // Converts from a base64buffer.
to_base64::to_base64(const std::vector<unsigned char>& bfr) : // Converts from a base64buffer.
BadConversion(true) { // No conversion yet ;-) BadConversion(true) { // No conversion yet ;-)
convert(&bfr[0], bfr.size()); // Recast the pointer and do it. convert(&bfr[0], bfr.size()); // Recast the pointer and do it.
} }


to_base64::to_base64(const vector<char>& bfr) : // Converts from a base64codec buffer.
to_base64::to_base64(const std::vector<char>& bfr) : // Converts from a base64codec buffer.
BadConversion(true) { // No conversion yet ;-) BadConversion(true) { // No conversion yet ;-)
convert(reinterpret_cast<const unsigned char*>(&bfr[0]), bfr.size()); // Do this to get it done. convert(reinterpret_cast<const unsigned char*>(&bfr[0]), bfr.size()); // Do this to get it done.
} }
convert(reinterpret_cast<const unsigned char*>(bfr), len); // Do this to get it done. convert(reinterpret_cast<const unsigned char*>(bfr), len); // Do this to get it done.
} }


to_base64::to_base64(const string& s) : // Converts from a c++ string.
to_base64::to_base64(const std::string& s) : // Converts from a c++ string.
BadConversion(true) { // No conversion yet ;-) BadConversion(true) { // No conversion yet ;-)
convert(reinterpret_cast<const unsigned char*>(s.c_str()), s.length()); // Do this to get it done. convert(reinterpret_cast<const unsigned char*>(s.c_str()), s.length()); // Do this to get it done.
} }
BadConversion = false; // If we get here we did ok. BadConversion = false; // If we get here we did ok.
} }


from_base64::from_base64(const vector<unsigned char>& bfr) : // Converts from a base64buffer.
from_base64::from_base64(const std::vector<unsigned char>& bfr) : // Converts from a base64buffer.
BadConversion(true) { // It's bad until we've done it. BadConversion(true) { // It's bad until we've done it.
convert(&bfr[0], bfr.size()); // Recast the pointer and do it. convert(&bfr[0], bfr.size()); // Recast the pointer and do it.
} }


from_base64::from_base64(const vector<char>& bfr) : // Converts from a buffer.
from_base64::from_base64(const std::vector<char>& bfr) : // Converts from a buffer.
BadConversion(true) { // It's bad until we've done it. BadConversion(true) { // It's bad until we've done it.
convert(reinterpret_cast<const unsigned char*>(&bfr[0]), bfr.size()); // This is how we do it. convert(reinterpret_cast<const unsigned char*>(&bfr[0]), bfr.size()); // This is how we do it.
} }


from_base64::from_base64(const string& s) : // Converts from a c++ string.
from_base64::from_base64(const std::string& s) : // Converts from a c++ string.
BadConversion(true) { // It's bad until we've done it. BadConversion(true) { // It's bad until we've done it.
convert(reinterpret_cast<const unsigned char*>(s.c_str()), s.length()); // This is how we do it. convert(reinterpret_cast<const unsigned char*>(s.c_str()), s.length()); // This is how we do it.
} }
return BadConversion; return BadConversion;
} }


} // end namespace codedweller

+ 16
- 14
base64codec.hpp 查看文件

// base64codec.hpp // base64codec.hpp
// Copyright (C) 2006 - 2009 MicroNeil Research Corporation
// BASE64 encoder decoder objects extending vectors
//
// Copyright (C) 2004-2020 MicroNeil Research Corporation.
//
// This software is released under the MIT license. See LICENSE.TXT.
//
// Tools for encoding and decoding base64 data.


#ifndef base64codec_included
#define base64codec_included
#pragma once


#include <vector> #include <vector>
#include <cstring> #include <cstring>
#include <string> #include <string>


using namespace std;
namespace codedweller {


typedef vector<unsigned char> base64buffer;
typedef std::vector<unsigned char> base64buffer;


class to_base64 : public base64buffer { // Converts binary data to base 64. class to_base64 : public base64buffer { // Converts binary data to base 64.
private: private:
void convert(const unsigned char* bfr, const int len); // Does the actual work. void convert(const unsigned char* bfr, const int len); // Does the actual work.


public: public:
to_base64(const vector<unsigned char>& bfr); // Converts from a base64buffer.
to_base64(const vector<char>& bfr); // Converts from a buffer.
to_base64(const string& s); // Converts from a c++ string.
to_base64(const std::vector<unsigned char>& bfr); // Converts from a base64buffer.
to_base64(const std::vector<char>& bfr); // Converts from a buffer.
to_base64(const std::string& s); // Converts from a c++ string.
to_base64(const char* s); // Converts from a c string. to_base64(const char* s); // Converts from a c string.
to_base64(const unsigned char* bfr, const int len); // Converts from a uchar buffer. to_base64(const unsigned char* bfr, const int len); // Converts from a uchar buffer.
to_base64(const char* bfr, const int len); // Converts from a char buffer. to_base64(const char* bfr, const int len); // Converts from a char buffer.
void convert(const unsigned char* bfr, const int len); // Does the actual work. void convert(const unsigned char* bfr, const int len); // Does the actual work.


public: public:
from_base64(const vector<unsigned char>& bfr); // Converts from a base64buffer.
from_base64(const vector<char>& bfr); // Converts from a buffer.
from_base64(const string& s); // Converts from a c++ string.
from_base64(const std::vector<unsigned char>& bfr); // Converts from a base64buffer.
from_base64(const std::vector<char>& bfr); // Converts from a buffer.
from_base64(const std::string& s); // Converts from a c++ string.
from_base64(const char*); // Converts from a c_string. from_base64(const char*); // Converts from a c_string.
bool Bad(); // True if conversion wasn't complete. bool Bad(); // True if conversion wasn't complete.
}; };



#endif
}

+ 603
- 63
configuration.cpp 查看文件

// configuration.cpp // configuration.cpp
// //
// (C) 2006 - 2009 MicroNeil Research Corporation.
// Copyright (C) 2004-2020 MicroNeil Research Corporation.
// //
// This program is part of the MicroNeil Research Open Library Project. For
// more information go to http://www.microneil.com/OpenLibrary/index.html
// This software is released under the MIT license. See LICENSE.TXT.
// //
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 2 of the License, or (at your
// option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along with
// this program; if not, write to the Free Software Foundation, Inc., 59 Temple
// Place, Suite 330, Boston, MA 02111-1307 USA

// See configuration.hpp for details
// Tools for efficiently parsing XML, usually in configuration files.


#include "configuration.hpp" #include "configuration.hpp"


using namespace std;
namespace codedweller {

//// Configuration Element /////////////////////////////////////////////////////

ConfigurationElement::ConfigurationElement(const char* Name) : // Construct with a cstring.
myName(std::string(Name)),
myParent(NULL),
myLine(0),
myIndex(0),
myLength(0),
myCleanFlag(true),
myInitOnInterpretFlag(false) {
}

ConfigurationElement::ConfigurationElement(const std::string Name) : // Construct with a c++ string.
myName(Name),
myParent(NULL),
myLine(0),
myIndex(0),
myLength(0),
myCleanFlag(true),
myInitOnInterpretFlag(false) {
}

ConfigurationElement::ConfigurationElement( // Construct sub element w/ cstring.
const char* Name,
ConfigurationElement& Parent) :

myName(std::string(Name)),
myParent(&Parent),
myLine(0),
myIndex(0),
myLength(0),
myCleanFlag(true),
myInitOnInterpretFlag(false) {
}

ConfigurationElement::ConfigurationElement( // Construct sub element w/ string.
const std::string Name,
ConfigurationElement& Parent) :

myName(Name),
myParent(&Parent),
myLine(0),
myIndex(0),
myLength(0),
myCleanFlag(true),
myInitOnInterpretFlag(false) {
}

std::string ConfigurationElement::Name() { return myName; } // Get the name of this element.

ConfigurationElement& ConfigurationElement::Parent() { // Get the parrent of this element.
if(NULL != myParent) { // If I have a parent
return (*myParent); // then I dereference and return it.
} // If I don't have a parent
return (*this); // then I return myself.
}

ConfigurationElement& ConfigurationElement::Parent( // Set the parrent of this element.
ConfigurationElement& Parent) { // Given this parent
myParent = &Parent; // I take and store it's address
return (*myParent); // then dereference and return it.
}

int ConfigurationElement::Line() { return myLine; } // Get the last line number.

int ConfigurationElement::Index() { return myIndex; } // Get the last data position.

int ConfigurationElement::Length() { return myLength; } // Get the last length.

void ConfigurationElement::notifyDirty() { myCleanFlag = false; } // Attributes do this when they change.

ConfigurationElement& ConfigurationElement::Element(const char* Name) { // Add a new sub element by c string name.
return Element(std::string(Name)); // Use the string name version
}

ConfigurationElement& ConfigurationElement::Element(const std::string Name) { // Add a new sub element by c++ string name.
ConfigurationElement* N = new ConfigurationElement( // Create a new Element with the
Name, // name provided and
(*this)); // myself as the parent.

myElements.push_back(N); // Add it to the list.
return (*N); // Return the new element.
}

ConfigurationElement& ConfigurationElement::Element( // Mapping factory for convenience,
const char* Name, // requires a name, of course,
ConfigurationTranslator& newTranslator) { // Add a Translator to this element.
return Element(std::string(Name), newTranslator); // Use the string name version
}

ConfigurationElement& ConfigurationElement::Element( // Mapping factory for convenience,
const char* Name, // requires a name, of course,
std::string& x, std::string init) { // Map to a string.
return Element(std::string(Name), x, init); // Use the string name version
}

ConfigurationElement& ConfigurationElement::Element( // Mapping factory for convenience,
const char* Name, // requires a name, of course,
int& x, int init, int radix) { // Map to an int.
return Element(std::string(Name), x, init, radix); // Use the string name version
}

ConfigurationElement& ConfigurationElement::Element( // Mapping factory for convenience,
const char* Name, // requires a name, of course,
double& x, double init) { // Map to a double.
return Element(std::string(Name), x, init); // Use the string name version
}

ConfigurationElement& ConfigurationElement::Element( // Mapping factory for convenience,
const char* Name, // requires a name, of course,
bool& x, bool init) { // Map to a boolean.
return Element(std::string(Name), x, init); // Use the string name version
}

ConfigurationElement& ConfigurationElement::End() { // Return this element's parent.
return Parent(); // Borrow Parent()
}

ConfigurationElement& ConfigurationElement::End(const char* Name) { // Check the name and return the parent
return End(std::string(Name)); // Borrow End(string)
}

ConfigurationElement& ConfigurationElement::End(const std::string Name) { // if the name is correct - or throw!
if(0 != Name.compare(myName)) { // If Name is not myName
throw EndNameDoesNotMatch(); // throw an exception!
} // If the names match then
return Parent(); // return the parent.
}

ConfigurationAttribute& ConfigurationElement::Attribute( // Add an attribute using a cstring.
const char* Name) { // Given this cstring name
return Attribute(std::string(Name)); // Convert it to a string and borrow
} // Attribute(string)

ConfigurationAttribute& ConfigurationElement::Attribute( // Mapping factory for convenience,
const char* Name, // requires a name, of course,
ConfigurationTranslator& newTranslator) { // Add a Translator to this element.
return Attribute(std::string(Name), newTranslator); // Borrow the string name version
}

ConfigurationAttribute& ConfigurationElement::Attribute( // Mapping factory for convenience,
const char* Name, // requires a name, of course,
std::string& x, std::string init) { // Map to a string.
return Attribute(std::string(Name), x, init); // Borrow the string name version
}

ConfigurationAttribute& ConfigurationElement::Attribute( // Mapping factory for convenience,
const char* Name, // requires a name, of course,
int& x, int init, int radix) { // Map to an int.
return Attribute(std::string(Name), x, init); // Borrow the string name version
}

ConfigurationAttribute& ConfigurationElement::Attribute( // Mapping factory for convenience,
const char* Name, // requires a name, of course,
double& x, double init) { // Map to a double.
return Attribute(std::string(Name), x, init); // Borrow the string name version
}

ConfigurationAttribute& ConfigurationElement::Attribute( // Mapping factory for convenience,
const char* Name, // requires a name, of course,
bool& x, bool init) { // Map to a boolean.
return Attribute(std::string(Name), x, init); // Borrow the string name version
}

ConfigurationElement& ConfigurationElement::setInitOnInterpret() { // Set the init on interpret flag.
myInitOnInterpretFlag = true; // Set the flag.
return(*this); // Dereference and return self.
}

ConfigurationElement& ConfigurationElement::atStartCall( // Add an atStart call-back.
Configurator& Functor) { // Given this Functor,
myStartConfigurators.push_back(&Functor); // add it to my atStart list then
return(*this); // dereference and return myself.
}

ConfigurationElement& ConfigurationElement::atEndCall( // Add an atEnd call-back.
Configurator& Functor) { // Given this Functor,
myEndConfigurators.push_back(&Functor); // add it to my atEnd list then
return(*this); // dereference and return myself.
}

ConfigurationElement& ConfigurationElement::Mnemonic( // Add a mnemonic using c strings.
const char* name, const char* value) { // Given char* and char*
return Mnemonic(std::string(name), std::string(value)); // make strings and borrow that method.
}

ConfigurationElement& ConfigurationElement::Mnemonic( // Add a mnemonic using mixed strings.
const char* name, const std::string value) { // Given char* and string
return Mnemonic(std::string(name), value); // make strings and borrow that method.
}

ConfigurationElement& ConfigurationElement::Mnemonic( // Add a mnemonic using mixed strings.
const std::string name, const char* value) { // Given string and char*
return Mnemonic(name, std::string(value)); // make strings and borrow that method.
}

ConfigurationElement& ConfigurationElement::Mnemonic( // Add a mnemonic using c++ strings.
const std::string name, const std::string value) { // Givent string and string
ConfigurationMnemonic* N = // Create a new Mnemonic
new ConfigurationMnemonic(name, value); // using the values provided,
myMnemonics.push_back(N); // add it to my list, then
return(*this); // dereference and return myself.
}

//// Configuration Attribute ///////////////////////////////////////////////////

ConfigurationAttribute::ConfigurationAttribute( // Attributes are constructed with a
const char* Name, ConfigurationElement& Parent) : // Name and a Parent.
myName(std::string(Name)), // We convert the name to a string.
myParent(Parent), // We just grab the parent.
myLine(0), // Everything else gets zeroed.
myIndex(0),
myLength(0) {
}

ConfigurationAttribute::ConfigurationAttribute( // Attributes are constrictued with a
const std::string Name, ConfigurationElement& Parent) : // Name and a Parent.
myName(Name), // We grab them and zero the rest.
myParent(Parent),
myLine(0),
myIndex(0),
myLength(0) {
}

std::string ConfigurationAttribute::Name() { // Get the name of this attribute.
return myName;
}

ConfigurationElement& ConfigurationAttribute::Parent() { // Get the parent of this attribute.
return myParent;
}

int ConfigurationAttribute::Line() { // Get the last line number.
return myLine;
}

int ConfigurationAttribute::Index() { // Get the last data position.
return myIndex;
}

int ConfigurationAttribute::Length() { // Get the last length.
return myLength;
}

ConfigurationElement& ConfigurationAttribute::Element( // Add a new sub element by c string name.
const char* Name) {
return myParent.Element(Name);
}

ConfigurationElement& ConfigurationAttribute::Element( // Add a new sub element by c++ string name.
const std::string Name) {
return myParent.Element(Name);
}

ConfigurationElement& ConfigurationAttribute::Element( // Mapping factory for convenience,
const char* Name, // requires a name, of course,
ConfigurationTranslator& newTranslator) { // Add a Translator to this element.
return myParent.Element(Name, newTranslator);
}

ConfigurationElement& ConfigurationAttribute::Element( // Mapping factory for convenience,
const char* Name, // requires a name, of course,
std::string& x, std::string init) { // Map to a string.
return myParent.Element(Name, x, init);
}

ConfigurationElement& ConfigurationAttribute::Element( // Mapping factory for convenience,
const char* Name, // requires a name, of course,
int& x, int init, int radix) { // Map to an int.
return myParent.Element(Name, x, init, radix);
}

ConfigurationElement& ConfigurationAttribute::Element( // Mapping factory for convenience,
const char* Name, // requires a name, of course,
double& x, double init) { // Map to a double.
return myParent.Element(Name, x, init);
}

ConfigurationElement& ConfigurationAttribute::Element( // Mapping factory for convenience,
const char* Name, // requires a name, of course,
bool& x, bool init) { // Map to a boolean.
return myParent.Element(Name, x, init);
}

ConfigurationElement& ConfigurationAttribute::Element( // Mapping factory for convenience,
const std::string Name, // requires a name, of course,
ConfigurationTranslator& newTranslator) { // Add a Translator to this element.
return myParent.Element(Name, newTranslator);
}

ConfigurationElement& ConfigurationAttribute::Element( // Mapping factory for convenience,
const std::string Name, // requires a name, of course,
std::string& x, std::string init) { // Map to a string.
return myParent.Element(Name, x, init);
}

ConfigurationElement& ConfigurationAttribute::Element( // Mapping factory for convenience,
const std::string Name, // requires a name, of course,
int& x, int init, int radix) { // Map to an int.
return myParent.Element(Name, x, init, radix);
}

ConfigurationElement& ConfigurationAttribute::Element( // Mapping factory for convenience,
const std::string Name, // requires a name, of course,
double& x, double init) { // Map to a double.
return myParent.Element(Name, x, init);
}

ConfigurationElement& ConfigurationAttribute::Element( // Mapping factory for convenience,
const std::string Name, // requires a name, of course,
bool& x, bool init) { // Map to a boolean.
return myParent.Element(Name, x, init);
}

ConfigurationElement& ConfigurationAttribute::End() { // Return this element's parent.
return myParent.End();
}

ConfigurationElement& ConfigurationAttribute::End(const char* Name) { // Check the name and return the parent
return myParent.End(Name);
}

ConfigurationElement& ConfigurationAttribute::End(const std::string Name) { // if the name is correct - or throw!
return myParent.End(Name);
}

ConfigurationAttribute& ConfigurationAttribute::Attribute( // Add an attribute using a cstring.
const char* Name) {
return myParent.Attribute(Name);
}

ConfigurationAttribute& ConfigurationAttribute::Attribute( // Add an attribute using a c++ string.
const std::string Name) {
return myParent.Attribute(Name);
}

ConfigurationAttribute& ConfigurationAttribute::Attribute( // Mapping factory for convenience,
const char* Name, // requires a name, of course,
ConfigurationTranslator& newTranslator) { // Add a Translator to this element.
return myParent.Attribute(Name, newTranslator);
}

ConfigurationAttribute& ConfigurationAttribute::Attribute( // Mapping factory for convenience,
const char* Name, // requires a name, of course,
std::string& x, std::string init) { // Map to a string.
return myParent.Attribute(Name, x, init);
}

ConfigurationAttribute& ConfigurationAttribute::Attribute( // Mapping factory for convenience,
const char* Name, // requires a name, of course,
int& x, int init, int radix) { // Map to an int.
return myParent.Attribute(Name, x, init, radix);
}

ConfigurationAttribute& ConfigurationAttribute::Attribute( // Mapping factory for convenience,
const char* Name, // requires a name, of course,
double& x, double init) { // Map to a double.
return myParent.Attribute(Name, x, init);
}

ConfigurationAttribute& ConfigurationAttribute::Attribute( // Mapping factory for convenience,
const char* Name, // requires a name, of course,
bool& x, bool init) { // Map to a boolean.
return myParent.Attribute(Name, x, init);
}

ConfigurationAttribute& ConfigurationAttribute::Attribute( // Mapping factory for convenience,
const std::string Name, // requires a name, of course,
ConfigurationTranslator& newTranslator) { // Add a Translator to this element.
return myParent.Attribute(Name, newTranslator);
}

ConfigurationAttribute& ConfigurationAttribute::Attribute( // Mapping factory for convenience,
const std::string Name, // requires a name, of course,
std::string& x, std::string init) { // Map to a string.
return myParent.Attribute(Name, x, init);
}

ConfigurationAttribute& ConfigurationAttribute::Attribute( // Mapping factory for convenience,
const std::string Name, // requires a name, of course,
int& x, int init, int radix) { // Map to an int.
return myParent.Attribute(Name, x, init, radix);
}

ConfigurationAttribute& ConfigurationAttribute::Attribute( // Mapping factory for convenience,
const std::string Name, // requires a name, of course,
double& x, double init) { // Map to a double.
return myParent.Attribute(Name, x, init);
}

ConfigurationAttribute& ConfigurationAttribute::Attribute( // Mapping factory for convenience,
const std::string Name, // requires a name, of course,
bool& x, bool init) { // Map to a boolean.
return myParent.Attribute(Name, x, init);
}

ConfigurationElement& ConfigurationAttribute::setInitOnInterpret() { // Set the init on interpret flag.
return myParent.setInitOnInterpret();
}

ConfigurationElement& ConfigurationAttribute::atStartCall( // Add an atStart call-back to this element.
Configurator& Functor) {
return myParent.atStartCall(Functor);
}

ConfigurationElement& ConfigurationAttribute::atEndCall( // Add an atEnd call-back to this element.
Configurator& Functor) {
return myParent.atEndCall(Functor);
}

ConfigurationAttribute& ConfigurationAttribute::Mnemonic( // Add a mnemonic using c strings.
const char* name, const char* value) { // Given char* and char*
return Mnemonic(std::string(name), std::string(value)); // make strings and borrow that method.
}

ConfigurationAttribute& ConfigurationAttribute::Mnemonic( // Add a mnemonic using mixed strings.
const char* name, const std::string value) { // Given char* and string
return Mnemonic(std::string(name), value); // make strings and borrow that method.
}

ConfigurationAttribute& ConfigurationAttribute::Mnemonic( // Add a mnemonic using mixed strings.
const std::string name, const char* value) { // Given string and char*
return Mnemonic(name, std::string(value)); // make strings and borrow that method.
}

ConfigurationAttribute& ConfigurationAttribute::Mnemonic( // Add a mnemonic using c++ strings.
const std::string name, const std::string value) { // Givent string and string
ConfigurationMnemonic* N = // Create a new Mnemonic
new ConfigurationMnemonic(name, value); // using the values provided,
myMnemonics.push_back(N); // add it to my list, then
return(*this); // dereference and return myself.
}

//// Configuration Data ////////////////////////////////////////////////////////

char ConfigurationData::Data(int Index) { // Returns char from Data[Index]
if(0 > Index || Index >= myBufferSize) { // Check that index is in range
return 0; // and return 0 if it is not.
} // If Index is within range then
return myDataBuffer[Index]; // return the byte requested.
}

int ConfigurationData::Index() { // Reads the current Index.
return myIndex;
}

int ConfigurationData::Index(int i) { // Changes the current Index.
if(0 > i || i >= myBufferSize) { // If i is out of range then
return myIndex; // return the current Index unchanged.
} // If i is within range then
myIndex = i; // change the Index to i and
return myIndex; // return the changed Index.
}

int ConfigurationData::Line() { // Reads the current Line number.
return myLine;
}

int ConfigurationData::addNewLines(int Count) { // Increments the Line number.
myLine += Count; // Add the number of new lines.
return myLine; // Return the current Line number.
}

//// Configuration Translator //////////////////////////////////////////////////

StringTranslator::StringTranslator( // Construct this with
std::string& Variable, // the variable to map,
std::string Initializer) : // and the default value.
myVariable(Variable),
myInitializer(Initializer) {
}

void StringTranslator::translate(const char* Value) { // Provide a translation method.
myVariable = std::string(Value); // String to String = simple copy.
}

void StringTranslator::initialize() { // Provide an initialization method.
myVariable = myInitializer; // Revert to the initializer value.
}

IntegerTranslator::IntegerTranslator( // Construct this with
int& Variable, // the variable to map,
int Initializer, // and the default value.
int Radix) : // For this one we also need a Radix.
myVariable(Variable),
myInitializer(Initializer),
myRadix(Radix) {
}

void IntegerTranslator::translate(const char* Value) { // Provide a translation method.
char* dummy; // Throw away ptr for strtol().
myVariable = strtol(Value, &dummy, myRadix); // Convert the string w/ strtol().
}

void IntegerTranslator::initialize() { // Provide an initialization method.
myVariable = myInitializer; // Revert to the initializer value.
}

DoubleTranslator::DoubleTranslator( // Construct this with
double& Variable, // the variable to map,
double Initializer) : // and the default value.
myVariable(Variable),
myInitializer(Initializer) {
}

void DoubleTranslator::translate(const char* Value) { // Provide a translation method.
char* dummy; // Throw away ptr for strtod().
myVariable = strtod(Value, &dummy); // Convert the string w/ strtod().
}

void DoubleTranslator::initialize() { // Provide an initialization method.
myVariable = myInitializer; // Revert to the initializer value.
}

BoolTranslator::BoolTranslator( // Construct this with
bool& Variable, // the variable to map,
bool Initializer) : // and the default value.
myVariable(Variable),
myInitializer(Initializer) {
}

void BoolTranslator::translate(const char* Value) { // Provide a translation method.
if(
(0 == strcmp(Value,"on")) ||
(0 == strcmp(Value,"true")) || // on, true, yes, and 1 are
(0 == strcmp(Value, "yes")) || // interpreted as a boolean true.
(0 == strcmp(Value, "1"))
) {
myVariable = true;
} else { // Anything else is interpreted as
myVariable = false; // boolean false.
}
}

void BoolTranslator::initialize() { // Provide an initialization method.
myVariable = myInitializer; // Revert to the initializer value.
}

//// Configuration Mnemonic ////////////////////////////////////////////////////

ConfigurationMnemonic::ConfigurationMnemonic( // To make one, provide both parts.
std::string Name, std::string Value) :
myName(Name),
myValue(Value) {
}

bool ConfigurationMnemonic::test(std::string Name) { // Test to see if this Mnemonic matches.
return (0 == Name.compare(myName)); // Return true if Name and myName match.
}

std::string ConfigurationMnemonic::Value() { // If it does then we will need it's value.
return myValue;
}


//// Helper functions ////////////////////////////////////////////////////////// //// Helper functions //////////////////////////////////////////////////////////


// Delete my attributes // Delete my attributes


if(0 < myAttributes.size()) { // If we have attributes... if(0 < myAttributes.size()) { // If we have attributes...
list<ConfigurationAttribute*>::iterator iAttribute; // Iterate through our attributes list.
std::list<ConfigurationAttribute*>::iterator iAttribute; // Iterate through our attributes list.
iAttribute = myAttributes.begin(); // Start at the beginning and iAttribute = myAttributes.begin(); // Start at the beginning and
while(iAttribute != myAttributes.end()) { // loop through the whole list. while(iAttribute != myAttributes.end()) { // loop through the whole list.
delete (*iAttribute); // Delete each attribute delete (*iAttribute); // Delete each attribute
// Delete my sub-elements // Delete my sub-elements


if(0 < myElements.size()) { // If we have elements... if(0 < myElements.size()) { // If we have elements...
list<ConfigurationElement*>::iterator iElement; // Iterate through our elements list.
std::list<ConfigurationElement*>::iterator iElement; // Iterate through our elements list.
iElement = myElements.begin(); // Start at the beginning and iElement = myElements.begin(); // Start at the beginning and
while(iElement != myElements.end()) { // loop through the whole list. while(iElement != myElements.end()) { // loop through the whole list.
delete (*iElement); // Delete each element delete (*iElement); // Delete each element
// Delete my mnemonics // Delete my mnemonics


if(0 < myMnemonics.size()) { // If we have mnemonics... if(0 < myMnemonics.size()) { // If we have mnemonics...
list<ConfigurationMnemonic*>::iterator iMnemonic; // Iterate through our mnemonics list.
std::list<ConfigurationMnemonic*>::iterator iMnemonic; // Iterate through our mnemonics list.
iMnemonic = myMnemonics.begin(); // Start at the beginning and iMnemonic = myMnemonics.begin(); // Start at the beginning and
while(iMnemonic != myMnemonics.end()) { // loop through the whole list. while(iMnemonic != myMnemonics.end()) { // loop through the whole list.
delete (*iMnemonic); // Delete each mnemonic delete (*iMnemonic); // Delete each mnemonic
// Delete my translators // Delete my translators


if(0 < myTranslators.size()) { // If we have translators... if(0 < myTranslators.size()) { // If we have translators...
list<ConfigurationTranslator*>::iterator iTranslator; // Iterate through our translators list.
std::list<ConfigurationTranslator*>::iterator iTranslator; // Iterate through our translators list.
iTranslator = myTranslators.begin(); // Start at the beginning and iTranslator = myTranslators.begin(); // Start at the beginning and
while(iTranslator != myTranslators.end()) { // loop through the whole list. while(iTranslator != myTranslators.end()) { // loop through the whole list.
delete (*iTranslator); // Delete each translator delete (*iTranslator); // Delete each translator
} }


ConfigurationElement& ConfigurationElement::Element( // Mapping factory for convenience, ConfigurationElement& ConfigurationElement::Element( // Mapping factory for convenience,
const string Name, // requires a name, of course,
const std::string Name, // requires a name, of course,
ConfigurationTranslator& newTranslator) { // Add a Translator to this element. ConfigurationTranslator& newTranslator) { // Add a Translator to this element.


ConfigurationElement* N = new ConfigurationElement( // Create a new Element with the ConfigurationElement* N = new ConfigurationElement( // Create a new Element with the
} }


ConfigurationElement& ConfigurationElement::Element( // Mapping factory for convenience, ConfigurationElement& ConfigurationElement::Element( // Mapping factory for convenience,
const string Name, // requires a name, of course,
string& x, string init) { // Map to a string.
const std::string Name, // requires a name, of course,
std::string& x, std::string init) { // Map to a string.


ConfigurationElement* N = new ConfigurationElement( // Create a new Element with the ConfigurationElement* N = new ConfigurationElement( // Create a new Element with the
Name, // name provided and Name, // name provided and
} }


ConfigurationElement& ConfigurationElement::Element( // Mapping factory for convenience, ConfigurationElement& ConfigurationElement::Element( // Mapping factory for convenience,
const string Name, // requires a name, of course,
const std::string Name, // requires a name, of course,
int& x, int init, int radix) { // Map to an int. int& x, int init, int radix) { // Map to an int.


ConfigurationElement* N = new ConfigurationElement( // Create a new Element with the ConfigurationElement* N = new ConfigurationElement( // Create a new Element with the
} }


ConfigurationElement& ConfigurationElement::Element( // Mapping factory for convenience, ConfigurationElement& ConfigurationElement::Element( // Mapping factory for convenience,
const string Name, // requires a name, of course,
const std::string Name, // requires a name, of course,
double& x, double init) { // Map to a double. double& x, double init) { // Map to a double.


ConfigurationElement* N = new ConfigurationElement( // Create a new Element with the ConfigurationElement* N = new ConfigurationElement( // Create a new Element with the
} }


ConfigurationElement& ConfigurationElement::Element( // Mapping factory for convenience, ConfigurationElement& ConfigurationElement::Element( // Mapping factory for convenience,
const string Name, // requires a name, of course,
const std::string Name, // requires a name, of course,
bool& x, bool init) { // Map to a boolean. bool& x, bool init) { // Map to a boolean.


ConfigurationElement* N = new ConfigurationElement( // Create a new Element with the ConfigurationElement* N = new ConfigurationElement( // Create a new Element with the
return (*N); // Return the new element. return (*N); // Return the new element.
} }


ConfigurationAttribute& ConfigurationElement::Attribute(const string Name) { // Add an attribute using a c++ string.
ConfigurationAttribute* N = // Create a new attribute by name and
new ConfigurationAttribute(Name, (*this)); // provide myself as the parent.
ConfigurationAttribute& ConfigurationElement::Attribute(const std::string Name) { // Add an attribute using a c++ string.
ConfigurationAttribute* N = // Create a new attribute by name and
new ConfigurationAttribute(Name, (*this)); // provide myself as the parent.


myCleanFlag = false; // New attributes make us dirty. myCleanFlag = false; // New attributes make us dirty.


} }


ConfigurationAttribute& ConfigurationElement::Attribute( // Mapping factory for convenience, ConfigurationAttribute& ConfigurationElement::Attribute( // Mapping factory for convenience,
const string Name, // requires a name, of course,
const std::string Name, // requires a name, of course,
ConfigurationTranslator& newTranslator) { // Add a Translator to this element. ConfigurationTranslator& newTranslator) { // Add a Translator to this element.


myCleanFlag = false; // New attributes make us dirty. myCleanFlag = false; // New attributes make us dirty.
} }


ConfigurationAttribute& ConfigurationElement::Attribute( // Mapping factory for convenience, ConfigurationAttribute& ConfigurationElement::Attribute( // Mapping factory for convenience,
const string Name, // requires a name, of course,
string& x, string init) { // Map to a string.
const std::string Name, // requires a name, of course,
std::string& x, std::string init) { // Map to a string.


myCleanFlag = false; // New attributes make us dirty. myCleanFlag = false; // New attributes make us dirty.


} }


ConfigurationAttribute& ConfigurationElement::Attribute( // Mapping factory for convenience, ConfigurationAttribute& ConfigurationElement::Attribute( // Mapping factory for convenience,
const string Name, // requires a name, of course,
const std::string Name, // requires a name, of course,
int& x, int init, int radix) { // Map to an int. int& x, int init, int radix) { // Map to an int.


myCleanFlag = false; // New attributes make us dirty. myCleanFlag = false; // New attributes make us dirty.
} }


ConfigurationAttribute& ConfigurationElement::Attribute( // Mapping factory for convenience, ConfigurationAttribute& ConfigurationElement::Attribute( // Mapping factory for convenience,
const string Name, // requires a name, of course,
const std::string Name, // requires a name, of course,
double& x, double init) { // Map to a double. double& x, double init) { // Map to a double.


myCleanFlag = false; // New attributes make us dirty. myCleanFlag = false; // New attributes make us dirty.
} }


ConfigurationAttribute& ConfigurationElement::Attribute( // Mapping factory for convenience, ConfigurationAttribute& ConfigurationElement::Attribute( // Mapping factory for convenience,
const string Name, // requires a name, of course,
const std::string Name, // requires a name, of course,
bool& x, bool init) { // Map to a boolean. bool& x, bool init) { // Map to a boolean.


myCleanFlag = false; // New attributes make us dirty. myCleanFlag = false; // New attributes make us dirty.
} }


ConfigurationElement& ConfigurationElement::mapTo( // Map to a string. ConfigurationElement& ConfigurationElement::mapTo( // Map to a string.
string& x, string init) { // Given a string and init value,
std::string& x, std::string init) { // Given a string and init value,
ConfigurationTranslator* N = // create a new translator for it ConfigurationTranslator* N = // create a new translator for it
new StringTranslator(x, init); // with the values i'm given, new StringTranslator(x, init); // with the values i'm given,
myTranslators.push_back(N); // push it onto my list, then myTranslators.push_back(N); // push it onto my list, then
// Initialize the elements below me // Initialize the elements below me


if(0 < myElements.size()) { // If we have elements... if(0 < myElements.size()) { // If we have elements...
list<ConfigurationElement*>::iterator iElement; // Iterate through our elements list.
std::list<ConfigurationElement*>::iterator iElement; // Iterate through our elements list.
iElement = myElements.begin(); // Start at the beginning and iElement = myElements.begin(); // Start at the beginning and
while(iElement != myElements.end()) { // loop through the whole list. while(iElement != myElements.end()) { // loop through the whole list.
(*iElement)->initialize(); // Initialize each element (*iElement)->initialize(); // Initialize each element
// Initialize my own translators // Initialize my own translators


if(0 < myTranslators.size()) { // If we have translators... if(0 < myTranslators.size()) { // If we have translators...
list<ConfigurationTranslator*>::iterator iTranslator; // Iterate through our translators list.
std::list<ConfigurationTranslator*>::iterator iTranslator; // Iterate through our translators list.
iTranslator = myTranslators.begin(); // Start at the beginning and iTranslator = myTranslators.begin(); // Start at the beginning and
while(iTranslator != myTranslators.end()) { // loop through the whole list. while(iTranslator != myTranslators.end()) { // loop through the whole list.
(*iTranslator)->initialize(); // Initialize each translator (*iTranslator)->initialize(); // Initialize each translator
// Initialize my own attributes // Initialize my own attributes


if(0 < myAttributes.size()) { // If we have attributes... if(0 < myAttributes.size()) { // If we have attributes...
list<ConfigurationAttribute*>::iterator iAttribute; // Iterate through our attributes list.
std::list<ConfigurationAttribute*>::iterator iAttribute; // Iterate through our attributes list.
iAttribute = myAttributes.begin(); // Start at the beginning and iAttribute = myAttributes.begin(); // Start at the beginning and
while(iAttribute != myAttributes.end()) { // loop through the whole list. while(iAttribute != myAttributes.end()) { // loop through the whole list.
(*iAttribute)->initialize(); // Initialize each attribute (*iAttribute)->initialize(); // Initialize each attribute
} }


void ConfigurationElement::runStartConfigurators(ConfigurationData& D) { // Does what it says ;-) void ConfigurationElement::runStartConfigurators(ConfigurationData& D) { // Does what it says ;-)
list<Configurator*>::iterator iConfigurator; // Iterate through our Configurators list.
std::list<Configurator*>::iterator iConfigurator; // Iterate through our Configurators list.
iConfigurator = myStartConfigurators.begin(); // Start at the beginning and iConfigurator = myStartConfigurators.begin(); // Start at the beginning and
while(iConfigurator != myStartConfigurators.end()) { // loop through the whole list. while(iConfigurator != myStartConfigurators.end()) { // loop through the whole list.
(** iConfigurator)(*this, D); // Launch each configurator with self. (** iConfigurator)(*this, D); // Launch each configurator with self.
} }


void ConfigurationElement::runEndConfigurators(ConfigurationData& D) { // Does what it says ;-) void ConfigurationElement::runEndConfigurators(ConfigurationData& D) { // Does what it says ;-)
list<Configurator*>::iterator iConfigurator; // Iterate through our Configurators list.
std::list<Configurator*>::iterator iConfigurator; // Iterate through our Configurators list.
iConfigurator = myEndConfigurators.begin(); // Start at the beginning and iConfigurator = myEndConfigurators.begin(); // Start at the beginning and
while(iConfigurator != myEndConfigurators.end()) { // loop through the whole list. while(iConfigurator != myEndConfigurators.end()) { // loop through the whole list.
(** iConfigurator)(*this, D); // Launch each configurator with self. (** iConfigurator)(*this, D); // Launch each configurator with self.


if(isalpha(Data.Data(Index))) { // If it looks like an attribute... if(isalpha(Data.Data(Index))) { // If it looks like an attribute...
bool ParseHappened = false; // Start pessimistically at each pass. bool ParseHappened = false; // Start pessimistically at each pass.
list<ConfigurationAttribute*>::iterator iAttribute; // Iterate through our attributes list.
std::list<ConfigurationAttribute*>::iterator iAttribute; // Iterate through our attributes list.
iAttribute = myAttributes.begin(); // Start at the beginning and iAttribute = myAttributes.begin(); // Start at the beginning and
while(iAttribute != myAttributes.end()) { // loop through the whole list. while(iAttribute != myAttributes.end()) { // loop through the whole list.
ParseHappened = (* iAttribute)->interpret(Data); // Have each attribute interpret(Data) ParseHappened = (* iAttribute)->interpret(Data); // Have each attribute interpret(Data)
NewLines = 0; // Reset our new lines count. NewLines = 0; // Reset our new lines count.
if(0 < myElements.size()) { // If we have elements check them. if(0 < myElements.size()) { // If we have elements check them.


list<ConfigurationElement*>::iterator iElement; // Iterate through our elements list.
std::list<ConfigurationElement*>::iterator iElement; // Iterate through our elements list.
iElement = myElements.begin(); // Start at the beginning and iElement = myElements.begin(); // Start at the beginning and
while(iElement != myElements.end()) { // loop through the whole list. while(iElement != myElements.end()) { // loop through the whole list.
ConfigurationElement& doNode = **iElement; // Grab the element we're on. ConfigurationElement& doNode = **iElement; // Grab the element we're on.
// Create the Content buffer... // Create the Content buffer...


int BfrSize = Stopdex - Startdex +1; // How big a buffer do we need? int BfrSize = Stopdex - Startdex +1; // How big a buffer do we need?
vector<char> heapBfr(BfrSize,0); // Make one that size.
std::vector<char> heapBfr(BfrSize,0); // Make one that size.
char* Bfr = &heapBfr[0]; char* Bfr = &heapBfr[0];


copyDataCountLines(Bfr, Data, Startdex, Stopdex); // Get our data and ignore our lines. copyDataCountLines(Bfr, Data, Startdex, Stopdex); // Get our data and ignore our lines.
// Translate our data by Mnemonic // Translate our data by Mnemonic


if(0 < myMnemonics.size()) { // If we have mnemonics... if(0 < myMnemonics.size()) { // If we have mnemonics...
list<ConfigurationMnemonic*>::iterator iMnemonic; // Iterate through our mnemonics list.
std::list<ConfigurationMnemonic*>::iterator iMnemonic; // Iterate through our mnemonics list.
iMnemonic = myMnemonics.begin(); // Start at the beginning and iMnemonic = myMnemonics.begin(); // Start at the beginning and
while(iMnemonic != myMnemonics.end()) { // loop through the whole list. while(iMnemonic != myMnemonics.end()) { // loop through the whole list.
if(true == ((*iMnemonic)->test(TranslationData))) { // Check to see if the mnemonic matches. if(true == ((*iMnemonic)->test(TranslationData))) { // Check to see if the mnemonic matches.


// Put our TranslationData through each Translator. // Put our TranslationData through each Translator.


list<ConfigurationTranslator*>::iterator iTranslator; // Iterate through our translators list.
std::list<ConfigurationTranslator*>::iterator iTranslator; // Iterate through our translators list.
iTranslator = myTranslators.begin(); // Start at the beginning and iTranslator = myTranslators.begin(); // Start at the beginning and
while(iTranslator != myTranslators.end()) { // loop through the whole list. while(iTranslator != myTranslators.end()) { // loop through the whole list.
(*iTranslator)->translate(TranslationData); // Pass the data to each one then (*iTranslator)->translate(TranslationData); // Pass the data to each one then
// Delete my mnemonics // Delete my mnemonics


if(0 < myMnemonics.size()) { // If we have mnemonics... if(0 < myMnemonics.size()) { // If we have mnemonics...
list<ConfigurationMnemonic*>::iterator iMnemonic; // Iterate through our mnemonics list.
std::list<ConfigurationMnemonic*>::iterator iMnemonic; // Iterate through our mnemonics list.
iMnemonic = myMnemonics.begin(); // Start at the beginning and iMnemonic = myMnemonics.begin(); // Start at the beginning and
while(iMnemonic != myMnemonics.end()) { // loop through the whole list. while(iMnemonic != myMnemonics.end()) { // loop through the whole list.
delete (*iMnemonic); // Delete each mnemonic delete (*iMnemonic); // Delete each mnemonic
// Delete my translators // Delete my translators


if(0 < myTranslators.size()) { // If we have translators... if(0 < myTranslators.size()) { // If we have translators...
list<ConfigurationTranslator*>::iterator iTranslator; // Iterate through our translators list.
std::list<ConfigurationTranslator*>::iterator iTranslator; // Iterate through our translators list.
iTranslator = myTranslators.begin(); // Start at the beginning and iTranslator = myTranslators.begin(); // Start at the beginning and
while(iTranslator != myTranslators.end()) { // loop through the whole list. while(iTranslator != myTranslators.end()) { // loop through the whole list.
delete (*iTranslator); // Delete each translator delete (*iTranslator); // Delete each translator
} }


ConfigurationAttribute& ConfigurationAttribute::mapTo( // Map to a string. ConfigurationAttribute& ConfigurationAttribute::mapTo( // Map to a string.
string& x, string init) { // Given a string and init value,
std::string& x, std::string init) { // Given a string and init value,
ConfigurationTranslator* N = // create a new translator for it ConfigurationTranslator* N = // create a new translator for it
new StringTranslator(x, init); // with the values i'm given, new StringTranslator(x, init); // with the values i'm given,
myTranslators.push_back(N); // push it onto my list, then myTranslators.push_back(N); // push it onto my list, then
void ConfigurationAttribute::initialize() { // Reset all translators to defaults. void ConfigurationAttribute::initialize() { // Reset all translators to defaults.


if(0 < myTranslators.size()) { // If we have translators... if(0 < myTranslators.size()) { // If we have translators...
list<ConfigurationTranslator*>::iterator iTranslator; // Iterate through our translators list.
std::list<ConfigurationTranslator*>::iterator iTranslator; // Iterate through our translators list.
iTranslator = myTranslators.begin(); // Start at the beginning and iTranslator = myTranslators.begin(); // Start at the beginning and
while(iTranslator != myTranslators.end()) { // loop through the whole list. while(iTranslator != myTranslators.end()) { // loop through the whole list.
(*iTranslator)->initialize(); // initialize each translator (*iTranslator)->initialize(); // initialize each translator
// Read our data. // Read our data.


int BfrSize = Stopdex - Startdex +1; // How big a buffer do we need? int BfrSize = Stopdex - Startdex +1; // How big a buffer do we need?
vector<char> heapBfr(BfrSize,0); // Make one that size.
std::vector<char> heapBfr(BfrSize,0); // Make one that size.
char* Bfr = &heapBfr[0]; char* Bfr = &heapBfr[0];


NewLines += copyDataCountLines(Bfr, Data, Startdex, Stopdex); // Get our data and count our lines. NewLines += copyDataCountLines(Bfr, Data, Startdex, Stopdex); // Get our data and count our lines.
// Translate our data by Mnemonic // Translate our data by Mnemonic


if(0 < myMnemonics.size()) { // If we have mnemonics... if(0 < myMnemonics.size()) { // If we have mnemonics...
list<ConfigurationMnemonic*>::iterator iMnemonic; // Iterate through our mnemonics list.
std::list<ConfigurationMnemonic*>::iterator iMnemonic; // Iterate through our mnemonics list.
iMnemonic = myMnemonics.begin(); // Start at the beginning and iMnemonic = myMnemonics.begin(); // Start at the beginning and
while(iMnemonic != myMnemonics.end()) { // loop through the whole list. while(iMnemonic != myMnemonics.end()) { // loop through the whole list.
if(true == ((*iMnemonic)->test(TranslationData))){ // Check to see if the mnemonic matches. if(true == ((*iMnemonic)->test(TranslationData))){ // Check to see if the mnemonic matches.
// Put our TranslationData through each Translator. // Put our TranslationData through each Translator.


if(0 < myTranslators.size()) { // We'd better have translators! if(0 < myTranslators.size()) { // We'd better have translators!
list<ConfigurationTranslator*>::iterator iTranslator; // Iterate through our translators list.
std::list<ConfigurationTranslator*>::iterator iTranslator; // Iterate through our translators list.
iTranslator = myTranslators.begin(); // Start at the beginning and iTranslator = myTranslators.begin(); // Start at the beginning and
while(iTranslator != myTranslators.end()) { // loop through the whole list. while(iTranslator != myTranslators.end()) { // loop through the whole list.
(*iTranslator)->translate(TranslationData); // Pass the data to each one and (*iTranslator)->translate(TranslationData); // Pass the data to each one and
myIndex(0), // Our Index is zero myIndex(0), // Our Index is zero
myLine(1) { // We start on line 1 myLine(1) { // We start on line 1
try { // Capture any throws. try { // Capture any throws.
ifstream CFGFile(FileName); // Open the file.
CFGFile.seekg(0,ios::end); // Seek to the end
std::ifstream CFGFile(FileName); // Open the file.
CFGFile.seekg(0,std::ios::end); // Seek to the end
myBufferSize = CFGFile.tellg(); // to find out what size it is. myBufferSize = CFGFile.tellg(); // to find out what size it is.
myDataBuffer = newCStringBuffer(myBufferSize); // Make a new buffer the right size. myDataBuffer = newCStringBuffer(myBufferSize); // Make a new buffer the right size.
CFGFile.seekg(0,ios::beg); // Seek to the beginning and
CFGFile.seekg(0,std::ios::beg); // Seek to the beginning and
CFGFile.read(myDataBuffer, myBufferSize); // read the file into the buffer. CFGFile.read(myDataBuffer, myBufferSize); // read the file into the buffer.
if(CFGFile.bad()) { // If the read failed, we're unusable! if(CFGFile.bad()) { // If the read failed, we're unusable!
delete[] myDataBuffer; // Delete the buffer delete[] myDataBuffer; // Delete the buffer
} // indicating there is no Data. } // indicating there is no Data.
} }


ConfigurationData::ConfigurationData(const string FileName) : // Raw constructor from file.
ConfigurationData::ConfigurationData(const std::string FileName) : // Raw constructor from file.
myDataBuffer(NULL), // No data buffer yet. myDataBuffer(NULL), // No data buffer yet.
myBufferSize(0), // No length yet. myBufferSize(0), // No length yet.
myIndex(0), // Our Index is zero myIndex(0), // Our Index is zero
myLine(1) { // We start on line 1 myLine(1) { // We start on line 1
try { // Capture any throws. try { // Capture any throws.
ifstream CFGFile(FileName.c_str()); // Open the file.
CFGFile.seekg(0,ios::end); // Seek to the end
std::ifstream CFGFile(FileName.c_str()); // Open the file.
CFGFile.seekg(0,std::ios::end); // Seek to the end
myBufferSize = CFGFile.tellg(); // to find out what size it is. myBufferSize = CFGFile.tellg(); // to find out what size it is.
myDataBuffer = newCStringBuffer(myBufferSize); // Make a new buffer the right size. myDataBuffer = newCStringBuffer(myBufferSize); // Make a new buffer the right size.
CFGFile.seekg(0,ios::beg); // Seek to the beginning and
CFGFile.seekg(0,std::ios::beg); // Seek to the beginning and
CFGFile.read(myDataBuffer, myBufferSize); // read the file into the buffer. CFGFile.read(myDataBuffer, myBufferSize); // read the file into the buffer.
if(CFGFile.bad()) { // If the read failed, we're unusable! if(CFGFile.bad()) { // If the read failed, we're unusable!
delete[] myDataBuffer; // Delete the buffer delete[] myDataBuffer; // Delete the buffer
} // true. } // true.
} }


} // End namespace codedweller

+ 87
- 108
configuration.hpp 查看文件

// configuration.hpp // configuration.hpp
// //
// (C) 2006 - 2009 MicroNeil Research Corporation.
// See http://www.codedweller.com for details.
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 2 of the License, or (at your
// option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along with
// this program; if not, write to the Free Software Foundation, Inc., 59 Temple
// Place, Suite 330, Boston, MA 02111-1307 USA
// Copyright (C) 2004-2020 MicroNeil Research Corporation.
// //
// This software is released under the MIT license. See LICENSE.TXT.


// What about this ============================================================= // What about this =============================================================


// The configuration module provides a platform for reading configuration files // The configuration module provides a platform for reading configuration files
// (or string data) containing well-formed xml and mapping that data to program // (or string data) containing well-formed xml and mapping that data to program
// variables. // variables.
//
// The idea is to provide the ability for an object or application to provide // The idea is to provide the ability for an object or application to provide
// a modular "configuration" object that models a hierarchical collection of // a modular "configuration" object that models a hierarchical collection of
// "settings" that can be represented easily in code and in xml. // "settings" that can be represented easily in code and in xml.


// Include This Header Once Only =============================================== // Include This Header Once Only ===============================================


#ifndef configuration_included
#define configuration_included
#pragma once


#include <string> #include <string>
#include <vector> #include <vector>
#include <cstdlib> #include <cstdlib>
#include <list> #include <list>


using namespace std;
namespace codedweller {


class ConfigurationElement; // Elements exist class ConfigurationElement; // Elements exist
class ConfigurationAttribute; // Attributes exist class ConfigurationAttribute; // Attributes exist


private: private:


string myName; // Elements have a name.
std::string myName; // Elements have a name.


// External important things I remember but don't touch... // External important things I remember but don't touch...


ConfigurationElement* myParent; // They may have a parrent. ConfigurationElement* myParent; // They may have a parrent.


list<Configurator*> myStartConfigurators; // Call these when we start Interpret()
list<Configurator*> myEndConfigurators; // Call these when we finish Interpret()
std::list<Configurator*> myStartConfigurators; // Call these when we start Interpret()
std::list<Configurator*> myEndConfigurators; // Call these when we finish Interpret()


// Internal / subordinate things I own and kill... // Internal / subordinate things I own and kill...


list<ConfigurationAttribute*> myAttributes; // They may have a list of attributes.
list<ConfigurationElement*> myElements; // They may have a list of sub-elements.
list<ConfigurationMnemonic*> myMnemonics; // They may have a list of mnemonics.
list<ConfigurationTranslator*> myTranslators; // They may have a list of translators.
std::list<ConfigurationAttribute*> myAttributes; // They may have a list of attributes.
std::list<ConfigurationElement*> myElements; // They may have a list of sub-elements.
std::list<ConfigurationMnemonic*> myMnemonics; // They may have a list of mnemonics.
std::list<ConfigurationTranslator*> myTranslators; // They may have a list of translators.


// During Interpret() operations we keep track of where we are seen... // During Interpret() operations we keep track of where we are seen...


public: public:


ConfigurationElement(const char* Name); // Must be constructed with a name ConfigurationElement(const char* Name); // Must be constructed with a name
ConfigurationElement(const string Name); // either c string or c++ string.
ConfigurationElement(const std::string Name); // either c string or c++ string.


ConfigurationElement(const char* Name, ConfigurationElement& Parent); // Sub-elements are constructed with a ConfigurationElement(const char* Name, ConfigurationElement& Parent); // Sub-elements are constructed with a
ConfigurationElement(const string Name, ConfigurationElement& Parent); // parrent.
ConfigurationElement(const std::string Name, ConfigurationElement& Parent); // parrent.


// Upon desctruction an element will delete all subordinate objects: // Upon desctruction an element will delete all subordinate objects:
// * All sub element objects. // * All sub element objects.


// Elements can be probed for some simple, useful things. // Elements can be probed for some simple, useful things.


string Name(); // Get the name of this element.
std::string Name(); // Get the name of this element.
ConfigurationElement& Parent(); // Get the parent of this element. ConfigurationElement& Parent(); // Get the parent of this element.
ConfigurationElement& Parent(ConfigurationElement& newParent); // Set the parent of this element. ConfigurationElement& Parent(ConfigurationElement& newParent); // Set the parent of this element.


// Elements can contain either data or sub-elements. // Elements can contain either data or sub-elements.


ConfigurationElement& Element(const char* Name); // Add a new sub element by c string name. ConfigurationElement& Element(const char* Name); // Add a new sub element by c string name.
ConfigurationElement& Element(const string Name); // Add a new sub element by c++ string name.
ConfigurationElement& Element(const std::string Name); // Add a new sub element by c++ string name.


//// Mapping element factory methods for convenience. //// Mapping element factory methods for convenience.
//// Root-Node elements are _usually_ empty and without attributes in xml //// Root-Node elements are _usually_ empty and without attributes in xml


ConfigurationElement& Element( // Mapping factory for convenience, ConfigurationElement& Element( // Mapping factory for convenience,
const char* Name, // requires a name, of course, const char* Name, // requires a name, of course,
string& x, string init = string("")); // Map to a string.
std::string& x, std::string init = std::string("")); // Map to a string.


ConfigurationElement& Element( // Mapping factory for convenience, ConfigurationElement& Element( // Mapping factory for convenience,
const char* Name, // requires a name, of course, const char* Name, // requires a name, of course,
// string versions // string versions


ConfigurationElement& Element( // Mapping factory for convenience, ConfigurationElement& Element( // Mapping factory for convenience,
const string Name, // requires a name, of course,
const std::string Name, // requires a name, of course,
ConfigurationTranslator& newTranslator); // Add a Translator to this element. ConfigurationTranslator& newTranslator); // Add a Translator to this element.


ConfigurationElement& Element( // Mapping factory for convenience, ConfigurationElement& Element( // Mapping factory for convenience,
const string Name, // requires a name, of course,
string& x, string init = string("")); // Map to a string.
const std::string Name, // requires a name, of course,
std::string& x, std::string init = std::string("")); // Map to a string.


ConfigurationElement& Element( // Mapping factory for convenience, ConfigurationElement& Element( // Mapping factory for convenience,
const string Name, // requires a name, of course,
const std::string Name, // requires a name, of course,
int& x, int init = 0, int radix = 0); // Map to an int. int& x, int init = 0, int radix = 0); // Map to an int.


ConfigurationElement& Element( // Mapping factory for convenience, ConfigurationElement& Element( // Mapping factory for convenience,
const string Name, // requires a name, of course,
const std::string Name, // requires a name, of course,
double& x, double init = 0.0); // Map to a double. double& x, double init = 0.0); // Map to a double.


ConfigurationElement& Element( // Mapping factory for convenience, ConfigurationElement& Element( // Mapping factory for convenience,
const string Name, // requires a name, of course,
const std::string Name, // requires a name, of course,
bool& x, bool init = false); // Map to a boolean. bool& x, bool init = false); // Map to a boolean.


// End methods for heading back up the tree at the end of an element. // End methods for heading back up the tree at the end of an element.


ConfigurationElement& End(); // Return this element's parent. ConfigurationElement& End(); // Return this element's parent.
ConfigurationElement& End(const char* Name); // Check the name and return the parent ConfigurationElement& End(const char* Name); // Check the name and return the parent
ConfigurationElement& End(const string Name); // if the name is correct - or throw!
ConfigurationElement& End(const std::string Name); // if the name is correct - or throw!


// Elements can have attributes. // Elements can have attributes.


ConfigurationAttribute& Attribute(const char* Name); // Add an attribute using a cstring. ConfigurationAttribute& Attribute(const char* Name); // Add an attribute using a cstring.
ConfigurationAttribute& Attribute(const string Name); // Add an attribute using a c++ string.
ConfigurationAttribute& Attribute(const std::string Name); // Add an attribute using a c++ string.


//// Mapping Attribute factory methods for convenience. //// Mapping Attribute factory methods for convenience.




ConfigurationAttribute& Attribute( // Mapping factory for convenience, ConfigurationAttribute& Attribute( // Mapping factory for convenience,
const char* Name, // requires a name, of course, const char* Name, // requires a name, of course,
string& x, string init = string("")); // Map to a string.
std::string& x, std::string init = std::string("")); // Map to a string.


ConfigurationAttribute& Attribute( // Mapping factory for convenience, ConfigurationAttribute& Attribute( // Mapping factory for convenience,
const char* Name, // requires a name, of course, const char* Name, // requires a name, of course,
// string versions // string versions


ConfigurationAttribute& Attribute( // Mapping factory for convenience, ConfigurationAttribute& Attribute( // Mapping factory for convenience,
const string Name, // requires a name, of course,
const std::string Name, // requires a name, of course,
ConfigurationTranslator& newTranslator); // Add a Translator to this element. ConfigurationTranslator& newTranslator); // Add a Translator to this element.


ConfigurationAttribute& Attribute( // Mapping factory for convenience, ConfigurationAttribute& Attribute( // Mapping factory for convenience,
const string Name, // requires a name, of course,
string& x, string init = string("")); // Map to a string.
const std::string Name, // requires a name, of course,
std::string& x, std::string init = std::string("")); // Map to a string.


ConfigurationAttribute& Attribute( // Mapping factory for convenience, ConfigurationAttribute& Attribute( // Mapping factory for convenience,
const string Name, // requires a name, of course,
const std::string Name, // requires a name, of course,
int& x, int init = 0, int radix = 0); // Map to an int. int& x, int init = 0, int radix = 0); // Map to an int.


ConfigurationAttribute& Attribute( // Mapping factory for convenience, ConfigurationAttribute& Attribute( // Mapping factory for convenience,
const string Name, // requires a name, of course,
const std::string Name, // requires a name, of course,
double& x, double init = 0.0); // Map to a double. double& x, double init = 0.0); // Map to a double.


ConfigurationAttribute& Attribute( // Mapping factory for convenience, ConfigurationAttribute& Attribute( // Mapping factory for convenience,
const string Name, // requires a name, of course,
const std::string Name, // requires a name, of course,
bool& x, bool init = false); // Map to a boolean. bool& x, bool init = false); // Map to a boolean.


// Elements can Initialize() at each Interpret() call. // Elements can Initialize() at each Interpret() call.
// converts it into the expected type, and sets one or more variables // converts it into the expected type, and sets one or more variables
// to the converted value. Usually - just one variable. // to the converted value. Usually - just one variable.


ConfigurationElement& mapTo(ConfigurationTranslator& newTranslator); // Add a Translator to this element.
ConfigurationElement& mapTo(string& x, string init = string("")); // Map to a string.
ConfigurationElement& mapTo(int& x, int init = 0, int radix = 0); // Map to an int.
ConfigurationElement& mapTo(double& x, double init = 0.0); // Map to a double.
ConfigurationElement& mapTo(bool& x, bool init = false); // Map to a boolean.
ConfigurationElement& mapTo(ConfigurationTranslator& newTranslator); // Add a Translator to this element.
ConfigurationElement& mapTo(std::string& x, std::string init = std::string("")); // Map to a string.
ConfigurationElement& mapTo(int& x, int init = 0, int radix = 0); // Map to an int.
ConfigurationElement& mapTo(double& x, double init = 0.0); // Map to a double.
ConfigurationElement& mapTo(bool& x, bool init = false); // Map to a boolean.


// An Element's contents may use some special mnemonics to make a // An Element's contents may use some special mnemonics to make a
// configuration easier to understand and less error prone. When the // configuration easier to understand and less error prone. When the
// contents match a mnemnoic then the translation of the mnemonic is // contents match a mnemnoic then the translation of the mnemonic is
// passed to the Translators instead of the raw contents. // passed to the Translators instead of the raw contents.


ConfigurationElement& Mnemonic(const char* name, const char* value); // Add a mnemonic using c strings.
ConfigurationElement& Mnemonic(const char* name, const string value); // Add a mnemonic using c & c++ strings.
ConfigurationElement& Mnemonic(const string name, const char* value); // Add a mnemonic using c++ & c strings.
ConfigurationElement& Mnemonic(const string name, const string value); // Add a mnemonic using c++ strings.
ConfigurationElement& Mnemonic(const char* name, const char* value); // Add a mnemonic using c strings.
ConfigurationElement& Mnemonic(const char* name, const std::string value); // Add a mnemonic using c & c++ strings.
ConfigurationElement& Mnemonic(const std::string name, const char* value); // Add a mnemonic using c++ & c strings.
ConfigurationElement& Mnemonic(const std::string name, const std::string value); // Add a mnemonic using c++ strings.


// The way data gets into an element tree is that it is Interpret()ed // The way data gets into an element tree is that it is Interpret()ed
// recursively. The data is loaded into a ConfigurationData object which // recursively. The data is loaded into a ConfigurationData object which


private: private:


string myName; // Elements have a name.
std::string myName; // Elements have a name.
ConfigurationElement& myParent; // They may have a parrent. ConfigurationElement& myParent; // They may have a parrent.


list<ConfigurationMnemonic*> myMnemonics; // They may have a list of mnemonics.
list<ConfigurationTranslator*> myTranslators; // They may have a list of translators.
std::list<ConfigurationMnemonic*> myMnemonics; // They may have a list of mnemonics.
std::list<ConfigurationTranslator*> myTranslators; // They may have a list of translators.


int myLine; // Last line number I was seen on. int myLine; // Last line number I was seen on.
int myIndex; // Last char position I was seen on. int myIndex; // Last char position I was seen on.


public: public:


ConfigurationAttribute(const char* Name, ConfigurationElement& Parent); // Sub-elements are constructed with a
ConfigurationAttribute(const string Name, ConfigurationElement& Parent); // parrent.
ConfigurationAttribute(const char* Name, ConfigurationElement& Parent); // Sub-elements are constructed with a
ConfigurationAttribute(const std::string Name, ConfigurationElement& Parent); // parrent.


// Attributes delete their Mnemonics and Translators when they go. // Attributes delete their Mnemonics and Translators when they go.
// See Elements for similar warnings about objects provided to // See Elements for similar warnings about objects provided to


// Attributes can be probed for some simple, useful things. // Attributes can be probed for some simple, useful things.


string Name(); // Get the name of this attribute.
std::string Name(); // Get the name of this attribute.
ConfigurationElement& Parent(); // Get the parent of this attribute. ConfigurationElement& Parent(); // Get the parent of this attribute.
int Line(); // Get the last line number. int Line(); // Get the last line number.
int Index(); // Get the last data position. int Index(); // Get the last data position.
//// For switching back to the parent element and adding new sub-elements. //// For switching back to the parent element and adding new sub-elements.


ConfigurationElement& Element(const char* Name); // Add a new sub element by c string name. ConfigurationElement& Element(const char* Name); // Add a new sub element by c string name.
ConfigurationElement& Element(const string Name); // Add a new sub element by c++ string name.
ConfigurationElement& Element(const std::string Name); // Add a new sub element by c++ string name.


//// Mapping element factory methods for convenience. //// Mapping element factory methods for convenience.
//// Root-Node elements are _usually_ empty and without attributes in xml //// Root-Node elements are _usually_ empty and without attributes in xml


ConfigurationElement& Element( // Mapping factory for convenience, ConfigurationElement& Element( // Mapping factory for convenience,
const char* Name, // requires a name, of course, const char* Name, // requires a name, of course,
string& x, string init = string("")); // Map to a string.
std::string& x, std::string init = std::string("")); // Map to a string.


ConfigurationElement& Element( // Mapping factory for convenience, ConfigurationElement& Element( // Mapping factory for convenience,
const char* Name, // requires a name, of course, const char* Name, // requires a name, of course,
// string versions // string versions


ConfigurationElement& Element( // Mapping factory for convenience, ConfigurationElement& Element( // Mapping factory for convenience,
const string Name, // requires a name, of course,
const std::string Name, // requires a name, of course,
ConfigurationTranslator& newTranslator); // Add a Translator to this element. ConfigurationTranslator& newTranslator); // Add a Translator to this element.


ConfigurationElement& Element( // Mapping factory for convenience, ConfigurationElement& Element( // Mapping factory for convenience,
const string Name, // requires a name, of course,
string& x, string init = string("")); // Map to a string.
const std::string Name, // requires a name, of course,
std::string& x, std::string init = std::string("")); // Map to a string.


ConfigurationElement& Element( // Mapping factory for convenience, ConfigurationElement& Element( // Mapping factory for convenience,
const string Name, // requires a name, of course,
const std::string Name, // requires a name, of course,
int& x, int init = 0, int radix = 0); // Map to an int. int& x, int init = 0, int radix = 0); // Map to an int.


ConfigurationElement& Element( // Mapping factory for convenience, ConfigurationElement& Element( // Mapping factory for convenience,
const string Name, // requires a name, of course,
const std::string Name, // requires a name, of course,
double& x, double init = 0.0); // Map to a double. double& x, double init = 0.0); // Map to a double.


ConfigurationElement& Element( // Mapping factory for convenience, ConfigurationElement& Element( // Mapping factory for convenience,
const string Name, // requires a name, of course,
const std::string Name, // requires a name, of course,
bool& x, bool init = false); // Map to a boolean. bool& x, bool init = false); // Map to a boolean.


// End methods for heading back up the tree at the end of an element. // End methods for heading back up the tree at the end of an element.


ConfigurationElement& End(); // Return this element's parent. ConfigurationElement& End(); // Return this element's parent.
ConfigurationElement& End(const char* Name); // Check the name and return the parent ConfigurationElement& End(const char* Name); // Check the name and return the parent
ConfigurationElement& End(const string Name); // if the name is correct - or throw!
ConfigurationElement& End(const std::string Name); // if the name is correct - or throw!


//// For adding new attributes to the parent element. //// For adding new attributes to the parent element.


ConfigurationAttribute& Attribute(const char* Name); // Add an attribute using a cstring. ConfigurationAttribute& Attribute(const char* Name); // Add an attribute using a cstring.
ConfigurationAttribute& Attribute(const string Name); // Add an attribute using a c++ string.
ConfigurationAttribute& Attribute(const std::string Name); // Add an attribute using a c++ string.


//// Mapping Attribute factory methods for convenience. //// Mapping Attribute factory methods for convenience.




ConfigurationAttribute& Attribute( // Mapping factory for convenience, ConfigurationAttribute& Attribute( // Mapping factory for convenience,
const char* Name, // requires a name, of course, const char* Name, // requires a name, of course,
string& x, string init = string("")); // Map to a string.
std::string& x, std::string init = std::string("")); // Map to a string.


ConfigurationAttribute& Attribute( // Mapping factory for convenience, ConfigurationAttribute& Attribute( // Mapping factory for convenience,
const char* Name, // requires a name, of course, const char* Name, // requires a name, of course,
// string versions // string versions


ConfigurationAttribute& Attribute( // Mapping factory for convenience, ConfigurationAttribute& Attribute( // Mapping factory for convenience,
const string Name, // requires a name, of course,
const std::string Name, // requires a name, of course,
ConfigurationTranslator& newTranslator); // Add a Translator to this element. ConfigurationTranslator& newTranslator); // Add a Translator to this element.


ConfigurationAttribute& Attribute( // Mapping factory for convenience, ConfigurationAttribute& Attribute( // Mapping factory for convenience,
const string Name, // requires a name, of course,
string& x, string init = string("")); // Map to a string.
const std::string Name, // requires a name, of course,
std::string& x, std::string init = std::string("")); // Map to a string.


ConfigurationAttribute& Attribute( // Mapping factory for convenience, ConfigurationAttribute& Attribute( // Mapping factory for convenience,
const string Name, // requires a name, of course,
const std::string Name, // requires a name, of course,
int& x, int init = 0, int radix = 0); // Map to an int. int& x, int init = 0, int radix = 0); // Map to an int.


ConfigurationAttribute& Attribute( // Mapping factory for convenience, ConfigurationAttribute& Attribute( // Mapping factory for convenience,
const string Name, // requires a name, of course,
const std::string Name, // requires a name, of course,
double& x, double init = 0.0); // Map to a double. double& x, double init = 0.0); // Map to a double.


ConfigurationAttribute& Attribute( // Mapping factory for convenience, ConfigurationAttribute& Attribute( // Mapping factory for convenience,
const string Name, // requires a name, of course,
const std::string Name, // requires a name, of course,
bool& x, bool init = false); // Map to a boolean. bool& x, bool init = false); // Map to a boolean.


//// Set Init On Interprete for the parent element. //// Set Init On Interprete for the parent element.
// apply to the parent element's contents. Here they are for use on this // apply to the parent element's contents. Here they are for use on this
// attribute. // attribute.


ConfigurationAttribute& mapTo(ConfigurationTranslator& newTranslator); // Add a Translator to this attribute.
ConfigurationAttribute& mapTo(string& x, string init = string("")); // Map to a string.
ConfigurationAttribute& mapTo(int& x, int init, int radix = 0); // Map to an int.
ConfigurationAttribute& mapTo(double& x, double init = 0.0); // Map to a double.
ConfigurationAttribute& mapTo(bool& x, bool init = false); // Map to a boolean.
ConfigurationAttribute& mapTo(ConfigurationTranslator& newTranslator); // Add a Translator to this attribute.
ConfigurationAttribute& mapTo(std::string& x, std::string init = std::string("")); // Map to a string.
ConfigurationAttribute& mapTo(int& x, int init, int radix = 0); // Map to an int.
ConfigurationAttribute& mapTo(double& x, double init = 0.0); // Map to a double.
ConfigurationAttribute& mapTo(bool& x, bool init = false); // Map to a boolean.


// Attributes can have mnemonics just like elements. // Attributes can have mnemonics just like elements.


ConfigurationAttribute& Mnemonic(const char* name, const char* value); // Add a mnemonic using a c string.
ConfigurationAttribute& Mnemonic(const char* name, const string value); // Add a mnemonic using c & c++ strings.
ConfigurationAttribute& Mnemonic(const string name, const char* value); // Add a mnemonic using c++ & c strings.
ConfigurationAttribute& Mnemonic(const string name, const string value); // Add a mnemonic using a c++ string.
ConfigurationAttribute& Mnemonic(const char* name, const char* value); // Add a mnemonic using a c string.
ConfigurationAttribute& Mnemonic(const char* name, const std::string value); // Add a mnemonic using c & c++ strings.
ConfigurationAttribute& Mnemonic(const std::string name, const char* value); // Add a mnemonic using c++ & c strings.
ConfigurationAttribute& Mnemonic(const std::string name, const std::string value); // Add a mnemonic using a c++ string.


// Attributes participate in the Interprete() task just like elements. // Attributes participate in the Interprete() task just like elements.


public: public:


ConfigurationData(const char* FileName); // Constructor from c string file name. ConfigurationData(const char* FileName); // Constructor from c string file name.
ConfigurationData(const string FileName); // Constructor from c++ string file name.
ConfigurationData(const std::string FileName); // Constructor from c++ string file name.
ConfigurationData(const char* Data, int Length); // Raw constructor from text buffer. ConfigurationData(const char* Data, int Length); // Raw constructor from text buffer.


~ConfigurationData(); // Destroys the internal buffer etc. ~ConfigurationData(); // Destroys the internal buffer etc.
int Line(); // Reads the current Line number. int Line(); // Reads the current Line number.
int addNewLines(int Count); // Increments the Line number. int addNewLines(int Count); // Increments the Line number.


stringstream Log; // Convenient Interpret log.
std::stringstream Log; // Convenient Interpret log.


}; };


// collection of the basic translators used for built-in mapTo()s. // collection of the basic translators used for built-in mapTo()s.


class ConfigurationTranslator { // Translators exist class ConfigurationTranslator { // Translators exist
public:
public:
virtual ~ConfigurationTranslator(){}; // Stop No Virt Dtor warnings. virtual ~ConfigurationTranslator(){}; // Stop No Virt Dtor warnings.
virtual void translate(const char* Value) = 0; // Pure virtual translator. virtual void translate(const char* Value) = 0; // Pure virtual translator.
virtual void initialize() = 0; // Pure virtual initializer. virtual void initialize() = 0; // Pure virtual initializer.


class StringTranslator : public ConfigurationTranslator { class StringTranslator : public ConfigurationTranslator {
private: private:
string& myVariable; // Variable to map.
string myInitializer; // Initial/Default value.
std::string& myVariable; // Variable to map.
std::string myInitializer; // Initial/Default value.


public: public:
StringTranslator( // Construct this with StringTranslator( // Construct this with
string& Variable, // the variable to map,
string Inititializer); // and the default value.
std::string& Variable, // the variable to map,
std::string Inititializer); // and the default value.


void translate(const char* Value); // Provide a translation method. void translate(const char* Value); // Provide a translation method.
void initialize(); // Provide an initialization method. void initialize(); // Provide an initialization method.


class ConfigurationMnemonic { // Mnemonics class ConfigurationMnemonic { // Mnemonics
private: private:
string myName; // What is the Mnemonic?
string myValue; // What is the translation?
std::string myName; // What is the Mnemonic?
std::string myValue; // What is the translation?


public: public:
ConfigurationMnemonic(string Name, string Value); // To make one, provide both parts.
bool test(string Name); // Test to see if this Mnemonic matches.
string Value(); // If it does then we will need it's value.
ConfigurationMnemonic(std::string Name, std::string Value); // To make one, provide both parts.
bool test(std::string Name); // Test to see if this Mnemonic matches.
std::string Value(); // If it does then we will need it's value.
}; };


//// Configurator ////////////////////////////////////////////////////////////// //// Configurator //////////////////////////////////////////////////////////////


class Configurator { // Configurators exist class Configurator { // Configurators exist
public: public:
virtual void operator()(ConfigurationElement& E, ConfigurationData& D) = 0; // Pure virtual configurator.
virtual void operator()(ConfigurationElement& E, ConfigurationData& D) = 0; // Pure virtual configurator.
virtual ~Configurator() {} // Virtual dtor keeps warnings away. virtual ~Configurator() {} // Virtual dtor keeps warnings away.
}; };


//// Include our inline methods ////////////////////////////////////////////////

#include "configuration.inline.hpp"

//// Utilities ///////////////////////////////////////////////////////////////// //// Utilities /////////////////////////////////////////////////////////////////


// SetTrueOnComplete Configurator ////////////////////////////////////////////// // SetTrueOnComplete Configurator //////////////////////////////////////////////
void operator()(ConfigurationElement& E, ConfigurationData& D); // Handle the operation. void operator()(ConfigurationElement& E, ConfigurationData& D); // Handle the operation.
}; };


#endif

// End Of Include Only Once

} // End namespace codedweller

+ 0
- 576
configuration.inline.hpp 查看文件

// 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 查看文件

// faults.hpp // faults.hpp
// //
// Copyright (C) MicroNeil Research Corporation 2009
// This file is part of the CodeDweller library.
// See www.codedweller.com for details.
// Copyright (C) 2004-2020 MicroNeil Research Corporation.
//
// This software is released under the MIT license. See LICENSE.TXT.
// //
// Faults and Checks are classes we can use in place of assert() to handle // Faults and Checks are classes we can use in place of assert() to handle
// unreasonable or necessary conditions in our code. They are constructed with // unreasonable or necessary conditions in our code. They are constructed with
// A Runtime...() throws a runtime_error (self) with it's description in what(). // A Runtime...() throws a runtime_error (self) with it's description in what().
// A Logic...() throws a logic_error (self) with it's description in what(). // A Logic...() throws a logic_error (self) with it's description in what().
#ifndef MNR_faults
#define MNR_faults
#pragma once
#include <stdexcept> #include <stdexcept>
#include <cstdlib> #include <cstdlib>
#include <iostream> #include <iostream>
#include <string> #include <string>
using namespace std;
namespace codedweller {
const int DefaultExitCode = EXIT_FAILURE; // Use this when no code is provided. const int DefaultExitCode = EXIT_FAILURE; // Use this when no code is provided.
private: private:
const string myDescription; // This is what I have to say.
const std::string myDescription; // This is what I have to say.
public: public:
AbortCheck(const string& Text) : myDescription(Text) {} // I am constructed with a description
AbortCheck(const std::string& Text) : myDescription(Text) {} // I am constructed with a description
void operator()(bool X) const { // Apply me like assert(exp) void operator()(bool X) const { // Apply me like assert(exp)
if(false == X) { // If the expression is false then we if(false == X) { // If the expression is false then we
cerr << myDescription << endl; // failed the check so we display our
std::cerr << myDescription << std::endl; // failed the check so we display our
abort(); // description and abort. abort(); // description and abort.
} }
} }
const string Description() { return myDescription; } // You can ask for my Description.
const std::string Description() { return myDescription; } // You can ask for my Description.
}; };
class AbortFault { // If this fault occurs we will abort. class AbortFault { // If this fault occurs we will abort.
private: private:
const string myDescription; // This is what I have to say.
const std::string myDescription; // This is what I have to say.
public: public:
AbortFault(const string& Text) : myDescription(Text) {} // I am constructed with a description
AbortFault(const std::string& Text) : myDescription(Text) {} // I am constructed with a description
void operator()(bool X) const { // Apply me like assert(! exp) void operator()(bool X) const { // Apply me like assert(! exp)
if(true == X) { // If the expression is true then we if(true == X) { // If the expression is true then we
cerr << myDescription << endl; // have a fault so we display our fault
std::cerr << myDescription << std::endl; // have a fault so we display our fault
abort(); // description and abort. abort(); // description and abort.
} }
} }
const string Description() const { return myDescription; } // You can ask for my Description.
const std::string Description() const { return myDescription; } // You can ask for my Description.
}; };
class ExitCheck { // If this check is false we will exit. class ExitCheck { // If this check is false we will exit.
private: private:
const string myDescription; // This is what I have to say.
const std::string myDescription; // This is what I have to say.
const int myExitCode; // This is what I send to exit(). const int myExitCode; // This is what I send to exit().
public: public:
ExitCheck(const string& Text, int Code=DefaultExitCode) : // I am constructed with a description
ExitCheck(const std::string& Text, int Code=DefaultExitCode) : // I am constructed with a description
myDescription(Text), myExitCode(Code) {} // and (optionlly) an exit code. myDescription(Text), myExitCode(Code) {} // and (optionlly) an exit code.
void operator()(bool X) const { // Apply me like assert(exp) void operator()(bool X) const { // Apply me like assert(exp)
if(false == X) { // If the expression is false then we if(false == X) { // If the expression is false then we
cerr << myDescription << endl; // failed the check so we display our
std::cerr << myDescription << std::endl; // failed the check so we display our
exit(myExitCode); // description and exit with our code. exit(myExitCode); // description and exit with our code.
} }
} }
const string Description() { return myDescription; } // You can ask for my Description.
const std::string Description() { return myDescription; } // You can ask for my Description.
const int ExitCode() { return myExitCode; } // You can ask for my ExitCode. const int ExitCode() { return myExitCode; } // You can ask for my ExitCode.
}; };
private: private:
const string myDescription; // This is what I have to say.
const std::string myDescription; // This is what I have to say.
const int myExitCode; // This is what I send to exit(). const int myExitCode; // This is what I send to exit().
public: public:
ExitFault(const string& Text, int Code=DefaultExitCode) : // I am constructed with a description
ExitFault(const std::string& Text, int Code=DefaultExitCode) : // I am constructed with a description
myDescription(Text), myExitCode(Code) {} // and (optionlly) an exit code. myDescription(Text), myExitCode(Code) {} // and (optionlly) an exit code.
void operator()(bool X) const { // Apply me like assert(! exp) void operator()(bool X) const { // Apply me like assert(! exp)
if(true == X) { // If the expression is true then we if(true == X) { // If the expression is true then we
cerr << myDescription << endl; // have a fault so we display our fault
std::cerr << myDescription << std::endl; // have a fault so we display our fault
exit(myExitCode); // description and exit with our code. exit(myExitCode); // description and exit with our code.
} }
} }
const string Description() const { return myDescription; } // You can ask for my Description.
const std::string Description() const { return myDescription; } // You can ask for my Description.
const int ExitCode() const { return myExitCode; } // You can ask for my ExitCode. const int ExitCode() const { return myExitCode; } // You can ask for my ExitCode.
}; };
class RuntimeCheck : public runtime_error { // Throw if this check fails.
class RuntimeCheck : public std::runtime_error { // Throw if this check fails.
public: public:
RuntimeCheck(const string& Text) : runtime_error(Text) {} // Construct me with a description.
RuntimeCheck(const std::string& Text) : std::runtime_error(Text) {} // Construct me with a description.
void operator()(bool X) const { // Apply me like assert(exp) void operator()(bool X) const { // Apply me like assert(exp)
if(false == X) { // If the expression is false then we if(false == X) { // If the expression is false then we
} }
}; };
class RuntimeFault : public runtime_error { // Throw if we find this fault.
class RuntimeFault : public std::runtime_error { // Throw if we find this fault.
public: public:
RuntimeFault(const string& Text) : runtime_error(Text) {} // Construct me with a description.
RuntimeFault(const std::string& Text) : std::runtime_error(Text) {} // Construct me with a description.
void operator()(bool X) const { // Apply me like assert(exp) void operator()(bool X) const { // Apply me like assert(exp)
if(true == X) { // If the expression is true then we if(true == X) { // If the expression is true then we
} }
}; };
class LogicCheck : public logic_error { // Throw if this check fails.
class LogicCheck : public std::logic_error { // Throw if this check fails.
public: public:
LogicCheck(const string& Text) : logic_error(Text) {} // Construct me with a description.
LogicCheck(const std::string& Text) : std::logic_error(Text) {} // Construct me with a description.
void operator()(bool X) const { // Apply me like assert(exp) void operator()(bool X) const { // Apply me like assert(exp)
if(false == X) { // If the expression is false then we if(false == X) { // If the expression is false then we
} }
}; };
class LogicFault : public logic_error { // Throw if we find this fault.
class LogicFault : public std::logic_error { // Throw if we find this fault.
public: public:
LogicFault(const string& Text) : logic_error(Text) {} // Construct me with a description.
LogicFault(const std::string& Text) : std::logic_error(Text) {} // Construct me with a description.
void operator()(bool X) const { // Apply me like assert(exp) void operator()(bool X) const { // Apply me like assert(exp)
if(true == X) { // If the expression is true then we if(true == X) { // If the expression is true then we
} }
}; };
#endif
// End Of Include MNR_faults Once Only =========================================
} // End namespace codedweller

+ 10
- 9
histogram.hpp 查看文件

// histogram.hpp // histogram.hpp
// Copyright (C) 2006 - 2009 MicroNeil Research Corporation
// Class to capture a histogram of events using a <set>
//
// Copyright (C) 2004-2020 MicroNeil Research Corporation.
//
// This software is released under the MIT license. See LICENSE.TXT.


#ifndef mn_histogram_included
#define mn_histogram_included
#pragma once


#include <set> #include <set>


using namespace std;
namespace codedweller {


/** The Histogram class is managed set of HistogramRecords. /** The Histogram class is managed set of HistogramRecords.
*** We play some naughty tricks with pointers to break the rules and *** We play some naughty tricks with pointers to break the rules and
class HistogramRecord { // A record to assocate a key and count. class HistogramRecord { // A record to assocate a key and count.
public: public:
int Key; // Here is the key. int Key; // Here is the key.
int Count; // Here is the count.
mutable int Count; // Here is the count.
HistogramRecord(const int NewKey) : // We must have a key to make one. HistogramRecord(const int NewKey) : // We must have a key to make one.
Key(NewKey), Count(0) {} // and a new one starts at count 0. Key(NewKey), Count(0) {} // and a new one starts at count 0.


} }
}; };


class Histogram : public set<HistogramRecord> { // A Histogram is a set of HistogramRecords
class Histogram : public std::set<HistogramRecord> { // A Histogram is a set of HistogramRecords
private: // and a private hit counter... private: // and a private hit counter...
int HitCount; int HitCount;
public: public:
int hit(const int EventKey, const int Adjustment = 1) { // hit() method increments a specific count. int hit(const int EventKey, const int Adjustment = 1) { // hit() method increments a specific count.
HistogramRecord E(EventKey); // First, make a record for the event key. HistogramRecord E(EventKey); // First, make a record for the event key.
insert(E); // Insert the new record (if it's not there). insert(E); // Insert the new record (if it's not there).
set<HistogramRecord>::iterator iE = // Find either the pre-existing or the new
std::set<HistogramRecord>::iterator iE = // Find either the pre-existing or the new
find(E); // record for this key. find(E); // record for this key.
int* C; // Play naughty pointer games to access int* C; // Play naughty pointer games to access
C = const_cast<int*>(&((*iE).Count)); // the Count for this record inside the C = const_cast<int*>(&((*iE).Count)); // the Count for this record inside the
} }
}; };


#endif
} // End namespace codedweller



+ 14
- 17
mangler.cpp 查看文件

// MANGLER.CPP // MANGLER.CPP
// //
// (C) 1984-2009 MicroNeil Research Corporation
// Copyright (C) 2004-2020 MicroNeil Research Corporation.
//
// This software is released under the MIT license. See LICENSE.TXT.
//
// Derived from Version 1 of Mangler Encryption Algorythm, 1984. // Derived from Version 1 of Mangler Encryption Algorythm, 1984.
// Derived from Version 2 of Mangler Encryption Algorythm, 1998. // Derived from Version 2 of Mangler Encryption Algorythm, 1998.
// //

// 20021008 _M
// Found and corrected range bug in ChaosDriver(void) where
// ~Position might access a location outside the fill. Replaced
// ~Position with Position^0xff which has the intended effect.

// 20020119 _M Version 3.0
//
// Mangler encryption engine object. // Mangler encryption engine object.
// Using new optimized chaos driver for uniformity experiments. // Using new optimized chaos driver for uniformity experiments.
// Important in this experiment is proof of highest possible entropy. // Important in this experiment is proof of highest possible entropy.


#include "mangler.hpp" #include "mangler.hpp"


unsigned char MANGLER::ChaosDriver(void) { // Return the current
namespace codedweller {

unsigned char Mangler::ChaosDriver(void) { // Return the current
return Fill[Fill[Position]^Fill[Position^0xff]]; // chaos engine output return Fill[Fill[Position]^Fill[Position^0xff]]; // chaos engine output
} // value. } // value.


// value of Position and determining the final output value and the Position // value of Position and determining the final output value and the Position
// value itself is used to add complexity to the output. // value itself is used to add complexity to the output.


unsigned char MANGLER::Rotate(unsigned char i) { // Bitwise rotates i
unsigned char Mangler::Rotate(unsigned char i) { // Bitwise rotates i
return ( return (
(i & 0x80)? // This operation is (i & 0x80)? // This operation is
(i<<1)+1: // described without (i<<1)+1: // described without
); );
} }


void MANGLER::ChaosDriver(unsigned char i) { // Drives chaos engine.
void Mangler::ChaosDriver(unsigned char i) { // Drives chaos engine.


// First we move our mixing position in the fill buffer forward. // First we move our mixing position in the fill buffer forward.


// same state with the same fill data characteristics or else the two // same state with the same fill data characteristics or else the two
// chaotic systems evolve to further divergent states. // chaotic systems evolve to further divergent states.


unsigned char MANGLER::Encrypt(unsigned char i) {
unsigned char Mangler::Encrypt(unsigned char i) {
unsigned char g = ChaosDriver() ^ i; // Take the output of the unsigned char g = ChaosDriver() ^ i; // Take the output of the
ChaosDriver(g); // chaos engine and use it ChaosDriver(g); // chaos engine and use it
return g; // to moduleate the input. return g; // to moduleate the input.
} // Then drive the engine } // Then drive the engine
// with the encrypted data. // with the encrypted data.


unsigned char MANGLER::Decrypt(unsigned char i) {
unsigned char Mangler::Decrypt(unsigned char i) {
unsigned char g = ChaosDriver() ^ i; // Take the output of the unsigned char g = ChaosDriver() ^ i; // Take the output of the
ChaosDriver(i); // chaos engine and use it ChaosDriver(i); // chaos engine and use it
return g; // to demodulate the input. return g; // to demodulate the input.
} // then drive the engine } // then drive the engine
// with the original input. // with the original input.
MANGLER::MANGLER(void) : Position(0) { // The default constructor sets
Mangler::Mangler(void) : Position(0) { // The default constructor sets
for(unsigned int c = 0;c<256;c++) // the key to the root primary for(unsigned int c = 0;c<256;c++) // the key to the root primary
Fill[c]=(unsigned char) c; // value and Position to 0. Fill[c]=(unsigned char) c; // value and Position to 0.
} }


} // End namespace codedweller

+ 10
- 8
mangler.hpp 查看文件

// MANGLER.HPP // MANGLER.HPP
// //
// (C) 1984-2009 MicroNeil Research Corporation
// Copyright (C) 2004-2020 MicroNeil Research Corporation.
//
// This software is released under the MIT license. See LICENSE.TXT.
//
// Derived from Version 1 of Mangler Encryption Algorythm, 1984. // Derived from Version 1 of Mangler Encryption Algorythm, 1984.
// Derived from Version 2 of Mangler Encryption Algorythm, 1998. // Derived from Version 2 of Mangler Encryption Algorythm, 1998.
// //
// 20020119 _M Mangler V3. // 20020119 _M Mangler V3.
// Mangler object header file. // Mangler object header file.
// If it's already been included, it doesn't need to be included again.


#ifndef _MANGLER_
#define _MANGLER_
#pragma once


class MANGLER {
namespace codedweller {

class Mangler {
private: private:


unsigned char Fill[256]; // Where to store the fill. unsigned char Fill[256]; // Where to store the fill.
unsigned char Encrypt(unsigned char i); // Returns encrypted data. unsigned char Encrypt(unsigned char i); // Returns encrypted data.
unsigned char Decrypt(unsigned char i); // Returns decrypted data. unsigned char Decrypt(unsigned char i); // Returns decrypted data.


MANGLER(void); // Default.
Mangler(void); // Default.
}; };


#endif

} // End namespace codedweller

+ 59
- 56
mishmash.cpp 查看文件

// mishmash.cpp (c) 20190407 _M
// non-cryptographic has for short strings
// mishmash.cpp
//
// Copyright (C) 2019-2020 MicroNeil Research Corporation.
//
// This software is released under the MIT license. See LICENSE.TXT.
//
// Mishmash is a non-cryptographic hash optimized for short strings.


#include "mishmash.hpp" #include "mishmash.hpp"


namespace codedweller { namespace codedweller {


uint32_t primes[256] {
1019, 1021, 1031, 1033, 1039, 1049, 1051, 1061,
1063, 1069, 1087, 1091, 1093, 1097, 1103, 1109,
1117, 1123, 1129, 1151, 1153, 1163, 1171, 1181,
1187, 1193, 1201, 1213, 1217, 1223, 1229, 1231,
1237, 1249, 1259, 1277, 1279, 1283, 1289, 1291,
1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361,
1367, 1373, 1381, 1399, 1409, 1423, 1427, 1429,
1433, 1439, 1447, 1451, 1453, 1459, 1471, 1481,
uint32_t primes[256] {
1019, 1021, 1031, 1033, 1039, 1049, 1051, 1061,
1063, 1069, 1087, 1091, 1093, 1097, 1103, 1109,
1117, 1123, 1129, 1151, 1153, 1163, 1171, 1181,
1187, 1193, 1201, 1213, 1217, 1223, 1229, 1231,
1237, 1249, 1259, 1277, 1279, 1283, 1289, 1291,
1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361,
1367, 1373, 1381, 1399, 1409, 1423, 1427, 1429,
1433, 1439, 1447, 1451, 1453, 1459, 1471, 1481,


1483, 1487, 1489, 1493, 1499, 1511, 1523, 1531,
1543, 1549, 1553, 1559, 1567, 1571, 1579, 1583,
1597, 1601, 1607, 1609, 1613, 1619, 1621, 1627,
1637, 1657, 1663, 1667, 1669, 1693, 1697, 1699,
1709, 1721, 1723, 1733, 1741, 1747, 1753, 1759,
1777, 1783, 1787, 1789, 1801, 1811, 1823, 1831,
1847, 1861, 1867, 1871, 1873, 1877, 1879, 1889,
1901, 1907, 1913, 1931, 1933, 1949, 1951, 1973,
1483, 1487, 1489, 1493, 1499, 1511, 1523, 1531,
1543, 1549, 1553, 1559, 1567, 1571, 1579, 1583,
1597, 1601, 1607, 1609, 1613, 1619, 1621, 1627,
1637, 1657, 1663, 1667, 1669, 1693, 1697, 1699,
1709, 1721, 1723, 1733, 1741, 1747, 1753, 1759,
1777, 1783, 1787, 1789, 1801, 1811, 1823, 1831,
1847, 1861, 1867, 1871, 1873, 1877, 1879, 1889,
1901, 1907, 1913, 1931, 1933, 1949, 1951, 1973,


1979, 1987, 1993, 1997, 1999, 2003, 2011, 2017,
2027, 2029, 2039, 2053, 2063, 2069, 2081, 2083,
2087, 2089, 2099, 2111, 2113, 2129, 2131, 2137,
2141, 2143, 2153, 2161, 2179, 2203, 2207, 2213,
2221, 2237, 2239, 2243, 2251, 2267, 2269, 2273,
2281, 2287, 2293, 2297, 2309, 2311, 2333, 2339,
2341, 2347, 2351, 2357, 2371, 2377, 2381, 2383,
2389, 2393, 2399, 2411, 2417, 2423, 2437, 2441,
2447, 2459, 2467, 2473, 2477, 2503, 2521, 2531,
2539, 2543, 2549, 2551, 2557, 2579, 2591, 2593,
2609, 2617, 2621, 2633, 2647, 2657, 2659, 2663,
2671, 2677, 2683, 2687, 2689, 2693, 2699, 2707,
2711, 2713, 2719, 2729, 2731, 2741, 2749, 2753,
2767, 2777, 2789, 2791, 2797, 2801, 2803, 2819,
2833, 2837, 2843, 2851, 2857, 2861, 2879, 2887,
2897, 2903, 2909, 2917, 2927, 2939, 2953, 2957
};
1979, 1987, 1993, 1997, 1999, 2003, 2011, 2017,
2027, 2029, 2039, 2053, 2063, 2069, 2081, 2083,
2087, 2089, 2099, 2111, 2113, 2129, 2131, 2137,
2141, 2143, 2153, 2161, 2179, 2203, 2207, 2213,
2221, 2237, 2239, 2243, 2251, 2267, 2269, 2273,
2281, 2287, 2293, 2297, 2309, 2311, 2333, 2339,
2341, 2347, 2351, 2357, 2371, 2377, 2381, 2383,
2389, 2393, 2399, 2411, 2417, 2423, 2437, 2441,
2447, 2459, 2467, 2473, 2477, 2503, 2521, 2531,
2539, 2543, 2549, 2551, 2557, 2579, 2591, 2593,
2609, 2617, 2621, 2633, 2647, 2657, 2659, 2663,
2671, 2677, 2683, 2687, 2689, 2693, 2699, 2707,
2711, 2713, 2719, 2729, 2731, 2741, 2749, 2753,
2767, 2777, 2789, 2791, 2797, 2801, 2803, 2819,
2833, 2837, 2843, 2851, 2857, 2861, 2879, 2887,
2897, 2903, 2909, 2917, 2927, 2939, 2953, 2957
};




inline size_t mod256(size_t n) noexcept { return (n & 0xff); }
inline uint32_t selectedPrime(size_t n) noexcept { return primes[mod256(n)]; }
inline size_t mod256(size_t n) noexcept { return (n & 0xff); }


uint32_t mishmash(const unsigned char* buffer, size_t length) noexcept {
uint64_t accumulator = selectedPrime(length);
for(size_t index = 0; index < length; index++) {
unsigned char byte = buffer[index];
accumulator += selectedPrime(index + accumulator);
accumulator *= selectedPrime(byte + accumulator);
accumulator += accumulator >> 32;
accumulator &= 0x00000fffffffffff;
}
return static_cast<uint32_t>(accumulator);
uint32_t mishmash(const unsigned char* buffer, size_t length) noexcept {
uint64_t accumulator = selectedPrime(length);
for(size_t index = 0; index < length; index++) {
unsigned char byte = buffer[index];
accumulator += selectedPrime(index + accumulator);
accumulator *= selectedPrime(byte + accumulator);
accumulator += accumulator >> 32;
accumulator &= 0x00000fffffffffff;
} }
return static_cast<uint32_t>(accumulator);
}


uint32_t mishmash(const std::string& s) noexcept {
return mishmash((const unsigned char*) s.c_str(), s.length());
}
uint32_t mishmash(const std::string& s) noexcept {
return mishmash((const unsigned char*) s.c_str(), s.length());
}


uint32_t mishmash(const std::vector<unsigned char>& v) noexcept {
return mishmash(v.data(), v.size());
}
uint32_t mishmash(const std::vector<unsigned char>& v) noexcept {
return mishmash(v.data(), v.size());
}


} }

+ 9
- 5
mishmash.hpp 查看文件

// mishmash.hpp (c) 20190407 _M
// mishmash.hpp//
// Copyright (C) 2019-2020 MicroNeil Research Corporation.
// //
// This software is released under the MIT license. See LICENSE.TXT.
//
// Mishamash is a non-cryptographic hash optimized for short strings.


#pragma once #pragma once
#include <string> #include <string>


namespace codedweller { namespace codedweller {


uint32_t mishmash(const unsigned char* buffer, size_t length) noexcept;
uint32_t mishmash(const std::string &s) noexcept;
uint32_t mishmash(const std::vector<unsigned char>& v) noexcept;
uint32_t mishmash(const unsigned char* buffer, size_t length) noexcept;
uint32_t mishmash(const std::string &s) noexcept;
uint32_t mishmash(const std::vector<unsigned char>& v) noexcept;


}
} // End namespace codedweller

+ 423
- 90
networking.cpp 查看文件

// networking.cpp // networking.cpp
// Copyright (C) 2006-2009 MicroNeil Research Corporation.
// //
// This program is part of the MicroNeil Research Open Library Project. For
// more information go to http://www.microneil.com/OpenLibrary/index.html
// Copyright (C) 2004-2020 MicroNeil Research Corporation.
// //
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 2 of the License, or (at your
// option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along with
// this program; if not, write to the Free Software Foundation, Inc., 59 Temple
// Place, Suite 330, Boston, MA 02111-1307 USA
//==============================================================================

// See networking.hpp for notes.
// See networking.inline.hpp for inlined methods & functions.
// This software is released under the MIT license. See LICENSE.TXT.


#include "networking.hpp" #include "networking.hpp"


Networking Network; // Finally creating the Network instance.
namespace codedweller {

Networking Network; // Creating _THE_ Network instance.

#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)

int Networking::getLastError() { // In windows you get the last error
return WSAGetLastError(); // from WSAGetLastError();
}

int Networking::setNonBlocking(hSocket socket) { // Set a winsock to non-blocking
unsigned long nonblocking = 1; // Create a flag...
int result = 0;
if(0 != ioctlsocket(socket, FIONBIO, &nonblocking)) { // Set the state of the socket.
result = -1; // If that fails then return -1.
}
return result; // Show 'em my motto!
}

int Networking::closeSocket(hSocket socket) { // Close a socket in winsock
return closesocket(socket); // wraps closesocket().
}

bool Networking::WouldBlock(int ErrorCode) { // ErrorCode matches [WSA]EWOULDBLOCK.
return (WSAEWOULDBLOCK == ErrorCode);
}

bool Networking::InProgress(int ErrorCode) { // ErrorCode matches [WSA]EINPROGRESS.
return( // [WSA]EALREADY also returns true.
WSAEINPROGRESS == ErrorCode || // In fact, on Win* platforms we could
WSAEALREADY == ErrorCode || // get any of these when retesting
WSAEWOULDBLOCK == ErrorCode || // open() for a connection.
WSAEINVAL == ErrorCode
);
}

bool Networking::IsConnected(int ErrorCode) { // ErrorCode matches [WSA]EISCONN.
return(WSAEISCONN == ErrorCode);
}

#else

//// GNU platform

int Networking::getLastError() { // In GNU you get the last error
return errno; // from errno;
}

int Networking::setNonBlocking(hSocket socket) { // Set a socket to non-blocking
int flags, result; // Grab a place to hold the flags.
flags = fcntl(socket, F_GETFL, 0); // Get the current flags.
result = fcntl(socket, F_SETFL, flags | O_NONBLOCK); // Set the NONBLOCK flag & return.
return result; // Return the result.
}

int Networking::closeSocket(hSocket socket) { // Close a socket in GNU
return close(socket); // wraps close().
}

bool Networking::WouldBlock(int ErrorCode) { // ErrorCode matches [WSA]EWOULDBLOCK.
return (EWOULDBLOCK == ErrorCode);
}

bool Networking::InProgress(int ErrorCode) { // ErrorCode matches [WSA]EINPROGRESS.
return( // [WSA]EALREADY also returns true.
EINPROGRESS == ErrorCode ||
EALREADY == ErrorCode
);
}

bool Networking::IsConnected(int ErrorCode) { // ErrorCode matches [WSA]EISCONN.
return(EISCONN == ErrorCode);
}

#endif

// End Platform Specific
////////////////////////////////////////////////////////////////////////////////
// Begin Platform Agnostic

//// class IP4Address //////////////////////////////////////////////////////////

IP4Address::IP4Address():IP(0){} // Blank constructor IP = 0.0.0.0
IP4Address::IP4Address(const unsigned long int newIP):IP(newIP){} // Constructor given unsigned long
IP4Address::IP4Address(const IP4Address& newIP):IP(newIP.IP){} // Constructor given an IP4Address

IP4Address::IP4Address(const char* newIP) { (*this) = newIP; } // Construcing with a cstring.
IP4Address::IP4Address(const std::string& newIP) { (*this) = newIP; } // Constructing with a cppstring.

IP4Address& IP4Address::operator=(const unsigned long int Right) { // Convert from unsigned long int.
IP = Right;
return *this;
}

IP4Address& IP4Address::operator=(const char* Right) { // Convert from c string.
IP = ntohl(inet_addr(Right));
return *this;
}

IP4Address& IP4Address::operator=(const std::string& Right) { // Convert from cpp string.
IP = ntohl(inet_addr(Right.c_str()));
return *this;
}

bool IP4Address::operator<(const IP4Address Right) const { // < Comparison.
return (IP < Right.IP);
}

bool IP4Address::operator>(const IP4Address Right) const { // > Comparison.
return (IP > Right.IP);
}

bool IP4Address::operator==(const IP4Address Right) const { // == Comparison.
return (IP == Right.IP);
}

bool IP4Address::operator!=(const IP4Address Right) const { // != Comparison.
return (IP != Right.IP);
}

bool IP4Address::operator<=(const IP4Address Right) const { // <= Comparison.
return (IP <= Right.IP);
}

bool IP4Address::operator>=(const IP4Address Right) const { // >= Comparison.
return (IP >= Right.IP);
}

//// class SocketAddress ///////////////////////////////////////////////////////

void SocketAddress::clear() {
memset(&Address, 0, sizeof(Address)); // Zero out the address strcuture
Address.sin_family = AF_INET; // Internet Address Family ip4
Address.sin_addr.s_addr = htonl(INADDR_ANY); // Any IP address
Address.sin_port = 0; // Zero means any port.
}

SocketAddress::SocketAddress() { // Constructor sets up w/ wildcards
clear(); // Conveniently, we can use clear() :-)
}

struct sockaddr_in* SocketAddress::getPtr_sockaddr_in() { // Returns a pointer to sockaddr_in.
return &Address; // Simply return it's address.
}

struct sockaddr* SocketAddress::getPtr_sockaddr() { // Returns a pointer to sockaddr.
return (struct sockaddr*) &Address;
}


socklen_t SocketAddress::getAddressSize() {
return sizeof(Address); // Return the size of the structure.
}

void SocketAddress::setAddress(unsigned long ipAddress) { // Set the IP address from an unsigned int
Address.sin_addr.s_addr = htonl(ipAddress); // Convert to network order and assign.
}

void SocketAddress::setAddress(char* ipString) { // Set the IP address from a cstring
Address.sin_addr.s_addr = inet_addr(ipString); // Convert to number and assign.
}

unsigned long SocketAddress::getAddress() { // Get the IP address as an unsigned int
return ntohl(Address.sin_addr.s_addr); // Convert to host order and return.
}

void SocketAddress::setPort(unsigned short port) { // Set the port address from an int
Address.sin_port = htons(port); // Convert to network order and set.
}

void SocketAddress::setPort(char* port) { // Set the port address from a cstring
setPort(atoi(port)); // Convert to int and set.
}

unsigned short SocketAddress::getPort() { // Get the port address as an unsigned int
return ntohs(Address.sin_port); // Convert to host order and return.
}

const char* SocketAddress::getPort(char* str) { // Get the port address into a cstring.
if(NULL == str) { // If the caller did not provide a
str = PortStringBuffer; // buffer to use then we will use ours.
}
sprintf(str,"%d",getPort()); // Get the port and convert to cstring.
return str; // Return the string we got.
}

//// class Socket //////////////////////////////////////////////////////////////

Socket::Socket() : // When starting up we are
Handle(INVALID_SOCKET), OpenSucceeded(false) { // not yet valid.
}

Socket::~Socket() { // When shutting down, be sure
if(INVALID_SOCKET != Handle) { // any open socket is closed without
Network.closeSocket(Handle); // throwing any exceptions.
}
}

void Socket::close() { // When we close,
if(INVALID_SOCKET != Handle) { // If the handle is open then
if(Network.closeSocket(Handle)) { // close the handle and check for error.
LastError = Network.getLastError(); // If there was an error record it.
if(!Network.WouldBlock(LastError)) { // If the error was not WOULDBLOCK
throw Networking::ControlError( // then throw a ControlError exception.
Network.DescriptiveError(
"Socket::close()", LastError));
}
} else { // If there was no error then
LastError = 0; // reset the LastError value.
}
Handle = INVALID_SOCKET; // and reset the handle to INVALID.
NonBlocking = false; // The default is Blocking.
OpenSucceeded = false; // After close, forget we opened.
}
}

hSocket Socket::getHandle() { // Returns the current Socket handle.
return Handle;
}

bool Socket::isNonBlocking() { // Returns true if socket is NonBlocking
return NonBlocking;
}

void Socket::makeNonBlocking() { // Sets the socket to NonBlocking mode.
if(0 > Network.setNonBlocking(Handle)) { // Feed the call through Network.
LastError = Network.getLastError(); // If it didn't work, go get the error.
NonBlocking = false; // We are NOT NonBlocking.
throw Networking::ControlError( // Throw a control error.
Network.DescriptiveError(
"Socket::makeNonBlocking()", LastError));
} else {
NonBlocking = true; // If we didn't throw, we're ON.
}
}

bool Socket::isReuseAddress() { return ReuseAddress; } // True if socket is set SO_REUSEADDR.
bool Socket::isReuseAddress(bool set) { return (ReuseAddress = set); } // Changes SO_REUSEADDR setting.

bool Socket::isOpen() { // True if the socket is open.
return(
INVALID_SOCKET != Handle && // A valid handle and
true == OpenSucceeded // a successful open operation
); // means we're open.
}

int Socket::getLastError() { // Returns the last error for this socket.
return LastError;
}

//// class TCPClient ///////////////////////////////////////////////////////////

TCPClient::TCPClient(TCPListener& L, hSocket H, SocketAddress& A) : // How to create a TCPClient.
MyListener(L) { // Capture our listener.
Handle = H; // Capture the new socket handle.
RemoteAddress = A; // Capture the client address.
ReadPointer = ReadBuffer; // Set the read position to zero.
DataLength = 0; // There is no data yet.
OpenSucceeded = true; // We're getting an open socket.
}

TCPClient::~TCPClient() { // When destroying a TCPClient
try{ if(isOpen()) close(); } catch(...) {} // silently close any open connections.
}

void TCPClient::open() { // We provide open() as unsupported.
throw Networking::NotSupportedError( // Throw an exception if this is called.
Network.DescriptiveError(
"TCPClient::open()", LastError));
}

bool TCPClient::ReadBufferIsEmpty() { // True if the ReadBuffer is empty.
return (0 >= DataLength); // We can check that with DataLength.
}

void TCPClient::fillReadBuffer() { // Fills the buffer from the socket.
LastError = 0; // Clear the LastError value.
ReadPointer = ReadBuffer; // Reset the ReadPointer.
DataLength = recv(Handle, ReadBuffer, sizeof(ReadBuffer), MSG_NOSIGNAL); // Try to read some data.

if(0 >= DataLength) { // If there was an error then
LastError = Network.getLastError(); // Grab the last error code.
DataLength = 0; // Correct the DataLength.
if(Network.WouldBlock(LastError)) { // If the error was WouldBlock then
return; // simply return - it's ok.
} else { // If it was a different error
throw Networking::SocketReadError( // then throw a ReadError.
Network.DescriptiveError(
"TCPClient::fillReadBuffer()", LastError));
}
} // If we succeeded then our ReadBuffer
} // assembly is in good shape.

bool TCPClient::isNonBlocking() { // Provided for MessagePort.
return Socket::isNonBlocking();
}

unsigned long TCPClient::getRemoteIP() { // Get remote IP as long.
return RemoteAddress.getAddress();
}

const char* TCPClient::getRemoteIP(char* str) { // Get IP as string.
return RemoteAddress.getAddress(str);
}

unsigned short TCPClient::getRemotePort() { // Get remote Port as unsigned short.
return RemoteAddress.getPort();
}

const char* TCPClient::getRemotePort(char* str) { // Get Port as string.
return RemoteAddress.getPort(str);
}

//// class TCPHost /////////////////////////////////////////////////////////////

TCPHost::~TCPHost() { // When destroying a TCPHost
try{ if(isOpen()) close(); } catch(...) {} // silently close any open connection.
}

bool TCPHost::ReadBufferIsEmpty() { // True if the ReadBuffer is empty.
return (0 >= DataLength); // We can check that with DataLength.
}

void TCPHost::fillReadBuffer() { // Fills the buffer from the socket.
LastError = 0; // Clear the LastError value.
ReadPointer = ReadBuffer; // Reset the ReadPointer.
DataLength = recv(Handle, ReadBuffer, sizeof(ReadBuffer), MSG_NOSIGNAL); // Try to read some data.

if(0 >= DataLength) { // If there was an error then
LastError = Network.getLastError(); // Grab the last error code.
DataLength = 0; // Correct the DataLength.
if(Network.WouldBlock(LastError)) { // If the error was WouldBlock then
return; // simply return - it's ok.
} else { // If it was a different error
throw Networking::SocketReadError( // then throw a ReadError.
Network.DescriptiveError(
"TCPHost::fillReadBuffer()", LastError));
}
} // If we succeeded then our ReadBuffer
} // assembly is in good shape.

bool TCPHost::isNonBlocking() { // Provided for MessagePort.
return Socket::isNonBlocking();
}

//// class TCPListener /////////////////////////////////////////////////////////

TCPListener::~TCPListener() { // When destroying a TCPListener
try{ close(); } catch(...) {} // silently close if not already done.
}


//// Platform Specific Stuff /////////////////////////////////////////////////// //// Platform Specific Stuff ///////////////////////////////////////////////////




// Error description handling for humans. // Error description handling for humans.


string Networking::DescriptiveError(string Msg, int Errno) { // Form a descriptive error w/ errno.
string s = ""; // Message string.
std::string Networking::DescriptiveError(std::string Msg, int Errno) { // Form a descriptive error w/ errno.
std::string s = ""; // Message string.


switch(Errno) { // Assign the appropriate message. switch(Errno) { // Assign the appropriate message.
case WSA_INVALID_HANDLE: s = "WSA_INVALID_HANDLE"; break; case WSA_INVALID_HANDLE: s = "WSA_INVALID_HANDLE"; break;
Msg.append(s); // then append it. Msg.append(s); // then append it.
} }
else { // If we don't know what Errno means else { // If we don't know what Errno means
ostringstream ErrNoMsg; // then say so and pass on Errno as
std::ostringstream ErrNoMsg; // then say so and pass on Errno as
ErrNoMsg << " UNKNOWN ErrorNumber = " << Errno; // well so someone can figure it out. ErrNoMsg << " UNKNOWN ErrorNumber = " << Errno; // well so someone can figure it out.
Msg.append(ErrNoMsg.str()); Msg.append(ErrNoMsg.str());
} }


// Error description handling for humans. // Error description handling for humans.


string Networking::DescriptiveError(string Msg, int Errno) { // Form a descriptive error w/ errno.
std::string Networking::DescriptiveError(std::string Msg, int Errno) { // Form a descriptive error w/ errno.
Msg.append(" "); Msg.append(strerror(Errno)); Msg.append(" "); Msg.append(strerror(Errno));
return Msg; return Msg;
}; };
return IP; // Return it. return IP; // Return it.
} }


IP4Address::operator string() const { // Assign to a string.
IP4Address::operator std::string() const { // Assign to a string.
char stringbfr[IPStringBufferSize]; // Grab a temporary buffer. char stringbfr[IPStringBufferSize]; // Grab a temporary buffer.
memset(stringbfr, 0, sizeof(stringbfr)); // Null out it's space. memset(stringbfr, 0, sizeof(stringbfr)); // Null out it's space.
int a0, a1, a2, a3; // Grab some integers. int a0, a1, a2, a3; // Grab some integers.
splitIP(IP, a0, a1, a2, a3); // Split the IP in the IP4Address. splitIP(IP, a0, a1, a2, a3); // Split the IP in the IP4Address.
sprintf(stringbfr, "%d.%d.%d.%d", a0, a1, a2, a3); // Format the octets. sprintf(stringbfr, "%d.%d.%d.%d", a0, a1, a2, a3); // Format the octets.
return string(stringbfr); // Return a string.
return std::string(stringbfr); // Return a string.
} }


//// SocketAddress methods ///////////////////////////////////////////////////// //// SocketAddress methods /////////////////////////////////////////////////////


if(!OpenStage2Complete) { // Do this stage only once. if(!OpenStage2Complete) { // Do this stage only once.
int result = // Bind our socket to the LocalAddress. int result = // Bind our socket to the LocalAddress.
::bind(
bind(
Handle, Handle,
LocalAddress.getPtr_sockaddr(), LocalAddress.getPtr_sockaddr(),
LocalAddress.getAddressSize()); LocalAddress.getAddressSize());
return NULL; // non blocking mode so we return return NULL; // non blocking mode so we return
} // NULL when we see them. } // NULL when we see them.
} }
// Set SO_NOSIGPIPE if needed
if( // On some systems we may have to
0 != SO_NOSIGPIPE && // use SO_NOSIPIPE but if they offer
0 == MSG_NOSIGNAL // MSG_NOSIGNAL we prefer that instead.
) {
int TurnedOn = 1; // Prepare to turn this option on.
int result = // Set SO_NOSIGPIPE.
setsockopt(
NewHandle,
SOL_SOCKET,
SO_NOSIGPIPE,
(char*) &TurnedOn,
sizeof(TurnedOn));
if(0 > result) { // If there was an error then
LastError = Network.getLastError(); // Capture the error information
Network.closeSocket(NewHandle); // close the handle (avoid leaks)
throw Networking::SocketSetSockOptError( // and throw a descriptive exception.
Network.DescriptiveError(
"TCPListener::acceptClient().setsockopt(SO_NOSIGPIPE)", LastError));
}
}
// Set SO_NOSIGPIPE if needed
if( // On some systems we may have to
0 != SO_NOSIGPIPE && // use SO_NOSIPIPE but if they offer
0 == MSG_NOSIGNAL // MSG_NOSIGNAL we prefer that instead.
) {
int TurnedOn = 1; // Prepare to turn this option on.
int result = // Set SO_NOSIGPIPE.
setsockopt(
NewHandle,
SOL_SOCKET,
SO_NOSIGPIPE,
(char*) &TurnedOn,
sizeof(TurnedOn));
if(0 > result) { // If there was an error then
LastError = Network.getLastError(); // Capture the error information
Network.closeSocket(NewHandle); // close the handle (avoid leaks)
throw Networking::SocketSetSockOptError( // and throw a descriptive exception.
Network.DescriptiveError(
"TCPListener::acceptClient().setsockopt(SO_NOSIGPIPE)", LastError));
}
}


// If things have gone well we can do what we came for. // If things have gone well we can do what we came for.


if(0 > size) // Watch out for bad sizes. if(0 > size) // Watch out for bad sizes.
throw Networking::SocketWriteError("TCPClient::transmit() 0 > size!"); throw Networking::SocketWriteError("TCPClient::transmit() 0 > size!");


LastError = 0; // No errors yet.
int ByteCount = 0; // No bytes sent yet this pass.
LastError = 0; // No errors yet.
int ByteCount = 0; // No bytes sent yet this pass.
ByteCount = send(Handle, bfr, size, MSG_NOSIGNAL); // Try to send and capture the count. ByteCount = send(Handle, bfr, size, MSG_NOSIGNAL); // Try to send and capture the count.
LastError = Network.getLastError(); // Grab any error code.
bool AnErrorOccurred = (0 > ByteCount); // How to know if an error occurred.
const int NoBytesSent = 0; // This is our "Would Block" result.
LastError = Network.getLastError(); // Grab any error code.
bool AnErrorOccurred = (0 > ByteCount); // How to know if an error occurred.
const int NoBytesSent = 0; // This is our "Would Block" result.
if(AnErrorOccurred) { // If there was an error check it out. if(AnErrorOccurred) { // If there was an error check it out.
if(Network.WouldBlock(LastError)) { // If the error was "Would Block" then if(Network.WouldBlock(LastError)) { // If the error was "Would Block" then
return NoBytesSent; // return no bytes sent (try again). return NoBytesSent; // return no bytes sent (try again).
"TCPClient::transmit().send()", LastError)); "TCPClient::transmit().send()", LastError));
} }
} }
return ByteCount; // Usually: return the sent byte count. return ByteCount; // Usually: return the sent byte count.
} }


LastError = 0; // Clear our LastError value. LastError = 0; // Clear our LastError value.
bool SuccessFlag = true; // Begin optimistically. bool SuccessFlag = true; // Begin optimistically.


// Set Socket Options
// Set Socket Options
if(!OpenStage1Complete) { // If we haven't done this yet: if(!OpenStage1Complete) { // If we haven't done this yet:
// Set SO_REUSEADDR if turned on
// Set SO_REUSEADDR if turned on
int ReuseAddress_Flag = (ReuseAddress? 1:0); // Setup an appropriate integer flag. int ReuseAddress_Flag = (ReuseAddress? 1:0); // Setup an appropriate integer flag.
int result = // Set SO_REUSEADDR before bind(). int result = // Set SO_REUSEADDR before bind().
setsockopt( setsockopt(
Network.DescriptiveError( Network.DescriptiveError(
"TCPHost::open().setsockopt(SO_REUSEADDR)", LastError)); "TCPHost::open().setsockopt(SO_REUSEADDR)", LastError));
} }
// Set SO_NOSIGPIPE if needed
if( // On some systems we may have to
0 != SO_NOSIGPIPE && // use SO_NOSIPIPE but if they offer
0 == MSG_NOSIGNAL // MSG_NOSIGNAL we prefer that instead.
) {
int TurnedOn = 1; // Prepare to turn this option on.
int result = // Set SO_NOSIGPIPE.
setsockopt(
Handle,
SOL_SOCKET,
SO_NOSIGPIPE,
(char*) &TurnedOn,
sizeof(TurnedOn));
if(0 > result) { // If there was an error then
SuccessFlag = false; // we did not succeed.
LastError = Network.getLastError(); // Capture the error information and
throw Networking::SocketSetSockOptError( // throw.
Network.DescriptiveError(
"TCPHost::open().setsockopt(SO_NOSIGPIPE)", LastError));
}
}
// Set SO_NOSIGPIPE if needed
if( // On some systems we may have to
0 != SO_NOSIGPIPE && // use SO_NOSIPIPE but if they offer
0 == MSG_NOSIGNAL // MSG_NOSIGNAL we prefer that instead.
) {
int TurnedOn = 1; // Prepare to turn this option on.
int result = // Set SO_NOSIGPIPE.
setsockopt(
Handle,
SOL_SOCKET,
SO_NOSIGPIPE,
(char*) &TurnedOn,
sizeof(TurnedOn));
if(0 > result) { // If there was an error then
SuccessFlag = false; // we did not succeed.
LastError = Network.getLastError(); // Capture the error information and
throw Networking::SocketSetSockOptError( // throw.
Network.DescriptiveError(
"TCPHost::open().setsockopt(SO_NOSIGPIPE)", LastError));
}
}
OpenStage1Complete = true; // Skip this section from now on. OpenStage1Complete = true; // Skip this section from now on.
} // Done with stage 1. } // Done with stage 1.




// End Platform Agnostic Stuff // End Platform Agnostic Stuff
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

} // End namespace codedweller

+ 53
- 68
networking.hpp 查看文件

// networking.hpp // networking.hpp
// Copyright (C) 2006-2009 MicroNeil Research Corporation.
// //
// This program is part of the MicroNeil Research Open Library Project. For
// more information go to http://www.microneil.com/OpenLibrary/index.html
// Copyright (C) 2004-2020 MicroNeil Research Corporation.
// //
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 2 of the License, or (at your
// option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along with
// this program; if not, write to the Free Software Foundation, Inc., 59 Temple
// Place, Suite 330, Boston, MA 02111-1307 USA
//==============================================================================
// This software is released under the MIT license. See LICENSE.TXT.


// The networking module abstracts network communications and provides a set // The networking module abstracts network communications and provides a set
// of objects for handling most tasks.

// 20080313 _M Refactored to throw proper runtime_error exceptions.
// of objects for handling most tasks on both win* and *nix.


// Include only once...
#ifndef M_Networking
#define M_Networking
#pragma once


#include <stdexcept> #include <stdexcept>
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
#include <cstring> #include <cstring>


using namespace std;

#include <cstdlib> #include <cstdlib>
#include <cstdio> #include <cstdio>
#include <cerrno> #include <cerrno>
//// Windows headers... //// Windows headers...


#include <winsock2.h> #include <winsock2.h>

namespace codedweller {

typedef int socklen_t; // Posix uses socklen_t so we mimic it. typedef int socklen_t; // Posix uses socklen_t so we mimic it.
typedef SOCKET hSocket; // Winx handles Socket is opaque. typedef SOCKET hSocket; // Winx handles Socket is opaque.

} // End namespace codedweller

#else #else


//// GNU Headers... //// GNU Headers...
#include <unistd.h> #include <unistd.h>
#include <fcntl.h> #include <fcntl.h>


namespace codedweller {

typedef int hSocket; // *nix uses int to handle a Socket. typedef int hSocket; // *nix uses int to handle a Socket.
const hSocket INVALID_SOCKET = -1; // -1 is the invalid Socket. const hSocket INVALID_SOCKET = -1; // -1 is the invalid Socket.


} // End namespace codedweller

#endif

namespace codedweller {

//// Handling SIGPIPE //////////////////////////////////////////////////////////

#ifndef MSG_NOSIGNAL
const int MSG_NOSIGNAL = 0; // Fake this if it isn't defined.
#endif

#ifndef SO_NOSIGPIPE
const int SO_NOSIGPIPE = 0; // Fake this if it isn't defined.
#endif #endif


//// Handling SIGPIPE //////////////////////////////////////////////////////////
#ifndef MSG_NOSIGNAL
const int MSG_NOSIGNAL = 0; // Fake this if it isn't defined.
#endif
#ifndef SO_NOSIGPIPE
const int SO_NOSIGPIPE = 0; // Fake this if it isn't defined.
#endif
//// Tuning and Constants ////////////////////////////////////////////////////// //// Tuning and Constants //////////////////////////////////////////////////////


const unsigned long LOCALHOST = 0x7F000001; // 127.0.0.1 as an integer. const unsigned long LOCALHOST = 0x7F000001; // 127.0.0.1 as an integer.
IP4Address(const IP4Address&); // Constructor given an IP4Address IP4Address(const IP4Address&); // Constructor given an IP4Address


IP4Address(const char* newIP); // Construcing with a cstring. IP4Address(const char* newIP); // Construcing with a cstring.
IP4Address(const string& newIP); // Constructing with a cppstring.
IP4Address(const std::string& newIP); // Constructing with a cppstring.


IP4Address& operator=(const unsigned long int Right); // Convert from unsigned long int. IP4Address& operator=(const unsigned long int Right); // Convert from unsigned long int.
IP4Address& operator=(const char* Right); // Convert from c string. IP4Address& operator=(const char* Right); // Convert from c string.
IP4Address& operator=(const string& Right); // Convert from cpp string.
IP4Address& operator=(const std::string& Right); // Convert from cpp string.


operator unsigned long int() const; operator unsigned long int() const;
operator string() const;
operator std::string() const;


bool operator<(const IP4Address Right) const; // < Comparison. bool operator<(const IP4Address Right) const; // < Comparison.
bool operator>(const IP4Address Right) const; // > Comparison. bool operator>(const IP4Address Right) const; // > Comparison.


public: public:


class NotSupportedError : public runtime_error { // Thrown when something can't be done.
public: NotSupportedError(const string& w):runtime_error(w) {}
class NotSupportedError : public std::runtime_error { // Thrown when something can't be done.
public: NotSupportedError(const std::string& w):runtime_error(w) {}
}; };
class InitializationError : public runtime_error { // Thrown if initialization fails.
public: InitializationError(const string& w):runtime_error(w) {}
class InitializationError : public std::runtime_error { // Thrown if initialization fails.
public: InitializationError(const std::string& w):runtime_error(w) {}
}; };
class ControlError : public runtime_error { // Thrown if control functions fail.
public: ControlError(const string& w):runtime_error(w) {}
class ControlError : public std::runtime_error { // Thrown if control functions fail.
public: ControlError(const std::string& w):runtime_error(w) {}
}; };
class SocketCreationError : public runtime_error { // Thrown if a call to socket() fails.
public: SocketCreationError(const string& w):runtime_error(w) {}
class SocketCreationError : public std::runtime_error { // Thrown if a call to socket() fails.
public: SocketCreationError(const std::string& w):runtime_error(w) {}
}; };
class SocketSetSockOptError : public runtime_error {
public: SocketSetSockOptError(const string& w):runtime_error(w) {} // Thrown if a call to setsockopt() fails.
class SocketSetSockOptError : public std::runtime_error { // Thrown if a call to setsockopt() fails.
public: SocketSetSockOptError(const std::string& w):runtime_error(w) {}
}; };
class SocketBindError : public runtime_error { // Thrown if a call to bind() fails.
public: SocketBindError(const string& w):runtime_error(w) {}
class SocketBindError : public std::runtime_error { // Thrown if a call to bind() fails.
public: SocketBindError(const std::string& w):runtime_error(w) {}
}; };
class SocketListenError : public runtime_error { // Thrown if a call to listen() fails.
public: SocketListenError(const string& w):runtime_error(w) {}
class SocketListenError : public std::runtime_error { // Thrown if a call to listen() fails.
public: SocketListenError(const std::string& w):runtime_error(w) {}
}; };
class SocketConnectError : public runtime_error { // Thrown if a call to connect() fails.
public: SocketConnectError(const string& w):runtime_error(w) {}
class SocketConnectError : public std::runtime_error { // Thrown if a call to connect() fails.
public: SocketConnectError(const std::string& w):runtime_error(w) {}
}; };
class SocketAcceptError : public runtime_error { // Thrown if a call to accept() fails.
public: SocketAcceptError(const string& w):runtime_error(w) {}
class SocketAcceptError : public std::runtime_error { // Thrown if a call to accept() fails.
public: SocketAcceptError(const std::string& w):runtime_error(w) {}
}; };
class SocketReadError : public runtime_error { // Thrown if a socket read call fails.
public: SocketReadError(const string& w):runtime_error(w) {}
class SocketReadError : public std::runtime_error { // Thrown if a socket read call fails.
public: SocketReadError(const std::string& w):runtime_error(w) {}
}; };
class SocketWriteError : public runtime_error { // Thrown if a socket write call fails.
public: SocketWriteError(const string& w):runtime_error(w) {}
class SocketWriteError : public std::runtime_error { // Thrown if a socket write call fails.
public: SocketWriteError(const std::string& w):runtime_error(w) {}
}; };


static string DescriptiveError(string Msg, int Errno); // Form a descriptive error w/ errno.
static std::string DescriptiveError(std::string Msg, int Errno); // Form a descriptive error w/ errno.


Networking(); Networking();
~Networking(); ~Networking();
// End of UDPBroadcaster class // End of UDPBroadcaster class
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////


//// Include Inline methods and functions...

#include "networking.inline.hpp"

#endif
// End include Networking.hpp only once...
} // End namespace codedweller

+ 0
- 375
networking.inline.hpp 查看文件

// 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 查看文件

// onetimepad.cpp // onetimepad.cpp
// Copyright (C) 2006-2007 MicroNeil Research Corporation
//
// Copyright (C) 2006-2020 MicroNeil Research Corporation.
//
// This software is released under the MIT license. See LICENSE.TXT.


#include "onetimepad.hpp" #include "onetimepad.hpp"
#include "timing.hpp" #include "timing.hpp"
#include <windows.h> #include <windows.h>
#include <wincrypt.h> #include <wincrypt.h>


namespace codedweller {

PadBuffer OneTimePad::Entropy(int Length) { // Get a PadBuffer full of randomness. PadBuffer OneTimePad::Entropy(int Length) { // Get a PadBuffer full of randomness.
PadBuffer Buffer(Length, 0); // Start by initializing the buffer. PadBuffer Buffer(Length, 0); // Start by initializing the buffer.
HCRYPTPROV provider = 0; // We will need a handle for the source. HCRYPTPROV provider = 0; // We will need a handle for the source.
return Buffer; // Return the data we got. return Buffer; // Return the data we got.
} }


} // End namespace codddweller

#else #else


//// *NIX Strong Entropy Source == /dev/urandom //////////////////////////////// //// *NIX Strong Entropy Source == /dev/urandom ////////////////////////////////


#include <fstream> #include <fstream>


namespace codedweller {

PadBuffer OneTimePad::Entropy(int Length) { // Get Length bytes of strong entropy. PadBuffer OneTimePad::Entropy(int Length) { // Get Length bytes of strong entropy.
PadBuffer Buffer(Length, 0); // Initialize a buffer to hold them. PadBuffer Buffer(Length, 0); // Initialize a buffer to hold them.
try { // Handle this in a try block. try { // Handle this in a try block.
ifstream Source("/dev/urandom", ios::binary); // Open /dev/urandom if possible.
std::ifstream Source("/dev/urandom", std::ios::binary); // Open /dev/urandom if possible.
Source.read(reinterpret_cast<char*>(&Buffer[0]), Length); // Read data into the buffer. Source.read(reinterpret_cast<char*>(&Buffer[0]), Length); // Read data into the buffer.
if(!Source.bad() && Source.gcount() == Length) { // If we got what we came for then if(!Source.bad() && Source.gcount() == Length) { // If we got what we came for then
StrongEntropyFlag = true; // we have strong cryptography. StrongEntropyFlag = true; // we have strong cryptography.
return Buffer; // Return the buffer. return Buffer; // Return the buffer.
} }


} // End namespace codedweller

#endif #endif


// End Platform Specific Bits // End Platform Specific Bits
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////


namespace codedweller {

// Lightweight entropy is built from a combination of the time in ms UTC that // Lightweight entropy is built from a combination of the time in ms UTC that
// the application was started, the number of milliseconds since that time in // the application was started, the number of milliseconds since that time in
// milliseconds, the number and times of calls to addLightweightEntropy(), and // milliseconds, the number and times of calls to addLightweightEntropy(), and
CombinedFill = CombinedFill ^ LightweightEntropyBuffer; // Pick up some previous state entropy. CombinedFill = CombinedFill ^ LightweightEntropyBuffer; // Pick up some previous state entropy.
unsigned char* PrimerBuffer = (unsigned char*) &CombinedFill; // Treat the value as a bunch of bytes. unsigned char* PrimerBuffer = (unsigned char*) &CombinedFill; // Treat the value as a bunch of bytes.
unsigned char* EntropyBuffer = (unsigned char*) &LightweightEntropyBuffer; // Likewise with the entropy buffer. unsigned char* EntropyBuffer = (unsigned char*) &LightweightEntropyBuffer; // Likewise with the entropy buffer.
for(int i = 0; i < sizeof(msclock); i++) { // Fold bytes into the mangler one
for(size_t i = 0; i < sizeof(msclock); i++) { // Fold bytes into the mangler one
EntropyBuffer[i] += // byte at a time, capturing the EntropyBuffer[i] += // byte at a time, capturing the
PadGenerator.Encrypt( // the results and using one extra PadGenerator.Encrypt( // the results and using one extra
PadGenerator.Encrypt(PrimerBuffer[i])); // round per byte to increase the PadGenerator.Encrypt(PrimerBuffer[i])); // round per byte to increase the


void OneTimePad::addEntropy() { // Add strong entropy if available. void OneTimePad::addEntropy() { // Add strong entropy if available.
PadBuffer Fill = Entropy(); // Grab the entropy bits to add. PadBuffer Fill = Entropy(); // Grab the entropy bits to add.
for(int i = 0; i < Fill.size(); i++) { // Pump them in one byte at a
for(size_t i = 0; i < Fill.size(); i++) { // Pump them in one byte at a
PadGenerator.Encrypt( // time and then run an extra PadGenerator.Encrypt( // time and then run an extra
PadGenerator.Encrypt(Fill.at(i))); // round per byte to increase the PadGenerator.Encrypt(Fill.at(i))); // round per byte to increase the
} // amount of guessing an attacker } // amount of guessing an attacker


void OneTimePad::addEntropy(PadBuffer Entropy) { // Add entropy from a given source. void OneTimePad::addEntropy(PadBuffer Entropy) { // Add entropy from a given source.
addLightweightEntropy(); // Start with some lightweight entropy. addLightweightEntropy(); // Start with some lightweight entropy.
for(int i = 0; i < Entropy.size(); i++) { // Then loop through the provided
for(size_t i = 0; i < Entropy.size(); i++) { // Then loop through the provided
PadGenerator.Encrypt( // entropy and mix it in with one PadGenerator.Encrypt( // entropy and mix it in with one
PadGenerator.Encrypt(Entropy.at(i))); // extra round per byte to increase PadGenerator.Encrypt(Entropy.at(i))); // extra round per byte to increase
} // the amount of guessing an attacker } // the amount of guessing an attacker
} // initial Mangler state. } // initial Mangler state.
} // The OneTimePad object is ready. } // The OneTimePad object is ready.


} // End namespace codedweller

+ 8
- 6
onetimepad.hpp 查看文件

// onetimepad.hpp // onetimepad.hpp
// Copyright (C) 2006 - 2007 MicroNeil Research Corporation
//
// Copyright (C) 2006-2020 MicroNeil Research Corporation.
//
// This software is released under the MIT license. See LICENSE.TXT.
// //
// This module leverages the Mangler encryption engine to create // This module leverages the Mangler encryption engine to create
// cryptographically strong one-time pads and random numbers upon request. // cryptographically strong one-time pads and random numbers upon request.
// started. Additional entropy can be provided by the application or again from // started. Additional entropy can be provided by the application or again from
// one of the core entropy generators (/dev/urandom or CryptGenRandom). // one of the core entropy generators (/dev/urandom or CryptGenRandom).
#ifndef onetimepad_included
#define onetimepad_included
#pragma once
#include <vector> #include <vector>
#include "mangler.hpp" #include "mangler.hpp"
using namespace std;
namespace codedweller {
typedef vector<unsigned char> PadBuffer;
typedef std::vector<unsigned char> PadBuffer;
class OneTimePad { // One Time Pad generator. class OneTimePad { // One Time Pad generator.
private: private:
}; };
#endif
} // End namespace codedweller

+ 11
- 26
threading.cpp 查看文件

// threading.cpp // threading.cpp
// //
// (C) 2006 - 2009 MicroNeil Research Corporation.
// Copyright (C) 2006-2020 MicroNeil Research Corporation.
// //
// This program is part of the MicroNeil Research Open Library Project. For
// more information go to http://www.microneil.com/OpenLibrary/index.html
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 2 of the License, or (at your
// option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along with
// this program; if not, write to the Free Software Foundation, Inc., 59 Temple
// Place, Suite 330, Boston, MA 02111-1307 USA

// For details on the Threading module and development history see threading.hpp
// This software is released under the MIT license. See LICENSE.TXT.


#include "threading.hpp" #include "threading.hpp"


using namespace std; // Introduce std namespace.
namespace codedweller {


ThreadManager Threads; // Master thread manager. ThreadManager Threads; // Master thread manager.


ScopeMutex ThereCanBeOnlyOne(MyMutex); // Protect our set -- a moment in time. ScopeMutex ThereCanBeOnlyOne(MyMutex); // Protect our set -- a moment in time.
ThreadStatusReport Answer; // Create our vector to hold the report. ThreadStatusReport Answer; // Create our vector to hold the report.
for( // Loop through all of the Threads. for( // Loop through all of the Threads.
set<Thread*>::iterator iT = KnownThreads.begin();
std::set<Thread*>::iterator iT = KnownThreads.begin();
iT != KnownThreads.end(); iT++ iT != KnownThreads.end(); iT++
) { // Grab each Threads' report. ) { // Grab each Threads' report.
Thread& X = *(*iT); // Handy reference to the Thread. Thread& X = *(*iT); // Handy reference to the Thread.


bool Thread::isBad() { return BadFlag; } // Return BadFlag state. bool Thread::isBad() { return BadFlag; } // Return BadFlag state.


const string Thread::MyFault() { return BadWhat; } // Return exception Bad fault if any.
const string Thread::MyName() { return MyThreadName; } // Return the instance name if any.
const std::string Thread::MyFault() { return BadWhat; } // Return exception Bad fault if any.
const std::string Thread::MyName() { return MyThreadName; } // Return the instance name if any.
const ThreadType& Thread::MyType() { return MyThreadType; } // Return the instance Thread Type. const ThreadType& Thread::MyType() { return MyThreadType; } // Return the instance Thread Type.
const ThreadState& Thread::MyState() { return (*MyThreadState); } // Thread state for this instance. const ThreadState& Thread::MyState() { return (*MyThreadState); } // Thread state for this instance.


CurrentThreadState(ThreadStarted); // Set the running state. CurrentThreadState(ThreadStarted); // Set the running state.
myTask(); // myTask() is called. myTask(); // myTask() is called.
} // myTask() should handle exceptions. } // myTask() should handle exceptions.
catch(exception& e) { // Unhandled exceptions are informative:
catch(const std::exception& e) { // Unhandled exceptions are informative:
BadFlag = true; // They mean the thread went bad but BadFlag = true; // They mean the thread went bad but
BadWhat = e.what(); // we have an idea what went wrong. BadWhat = e.what(); // we have an idea what went wrong.
} // We shouldn't get other kinds of } // We shouldn't get other kinds of
CurrentThreadState(ThreadInitialized); // Set our initialized state. CurrentThreadState(ThreadInitialized); // Set our initialized state.
} }


Thread::Thread(const ThreadType& T, const string N) : // Construct with specific Type/Name
Thread::Thread(const ThreadType& T, const std::string N) : // Construct with specific Type/Name
MyThreadType(T), // Use generic Thread Type. MyThreadType(T), // Use generic Thread Type.
MyThreadName(N), // Use a generic Thread Name. MyThreadName(N), // Use a generic Thread Name.
MyThread(NULL), // Null the thread handle. MyThread(NULL), // Null the thread handle.
CurrentThreadState(ThreadInitialized); // Set our initialized state. CurrentThreadState(ThreadInitialized); // Set our initialized state.
} }


Thread::Thread(const ThreadType& T, const string N) : // POSIX Specific Thread Constructor.
Thread::Thread(const ThreadType& T, const std::string N) : // POSIX Specific Thread Constructor.
MyThreadType(T), // Use a generic Thread Type. MyThreadType(T), // Use a generic Thread Type.
MyThreadName(N), // Use a generic Thread Name. MyThreadName(N), // Use a generic Thread Name.
RunningFlag(false), // Can't be running yet. RunningFlag(false), // Can't be running yet.


// End Production Gateway // End Production Gateway
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

} // End namespace codedweller

+ 80
- 116
threading.hpp 查看文件

// threading.hpp // threading.hpp
// //
// (C) 2006 - 2009 MicroNeil Research Corporation.
// Copyright (C) 2004-2020 MicroNeil Research Corporation.
// //
// This program is part of the MicroNeil Research Open Library Project. For
// more information go to http://www.microneil.com/OpenLibrary/index.html
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 2 of the License, or (at your
// option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along with
// this program; if not, write to the Free Software Foundation, Inc., 59 Temple
// Place, Suite 330, Boston, MA 02111-1307 USA
// This software is released under the MIT license. See LICENSE.TXT.


// The "Threading" module is a basic, cross-platform, multi-threading tool kit. // The "Threading" module is a basic, cross-platform, multi-threading tool kit.
// The differences between posix compatible systems and win32 based systems are // The differences between posix compatible systems and win32 based systems are
// here are designed to cover all of the basics efficiently while hiding the // here are designed to cover all of the basics efficiently while hiding the
// required under-cover work. // required under-cover work.


// A lot of this module is coded here in the header with the inline keyword
// because it is likely that the more basic objects can be efficiently compiled
// as inline abstractions to native calls. Really basic systems won't need
// anything beyond what is in this file.

// 20070202.1601 _M Further research has suggested that using a Semaphore in
// WIN32 environments in place of a CRITICAL_SECTION may provide the best
// performance and stability on all platforms. Specifically, SMP platforms may
// race and waste resources with CRITICAL_SECTIONs and in those cases it is
// recommended that the CRITICAL_SECTIONs may be "throttled" using Semaphores
// to limit the number of threads that may contend for a critical section. It
// is also suggested that if the Semaphore has an initialization value of 1
// the CRITICAL_SECTION is redundant. So this code has been modified to do
// precisely that!
//
// This new version also includes a ProductionGateway object that simplifies
// the producer/consumer model. The object keeps track of the number of calls
// to produce() and consume() and ensures that threads will block on consume()
// until a sufficient number of calls to produce() are made. That is, for every
// one call to produce(), a call to consume() will be allowed to proceed. The
// object also allows for the potentially asynchronous nature of these calls.

// 20070530.1751 _M Added top level exception handling in threads along with
// isRunning() and isBad() methods.

// 20060528.1647 _M All of the basics are complete and tested on both WIN32 and
// RHEL4 single and multiple processors.

// Include MNR_threading Once Only =============================================

#ifndef MNR_threading
#define MNR_threading
#pragma once


#include <set> #include <set>
#include <vector> #include <vector>
#include <string> #include <string>
#include <queue>
#include "faults.hpp"
#include <queue>
#include "faults.hpp"


using namespace std;
namespace codedweller {


class ThreadManager; // ThreadManager does exist. class ThreadManager; // ThreadManager does exist.
extern ThreadManager Threads; // Master thread manager. extern ThreadManager Threads; // Master thread manager.


class ThreadState { // Thread State Object. class ThreadState { // Thread State Object.
public: public:
const string Name; // Text name of thread descriptor.
ThreadState(string N) : Name(N) {} // Constructor requires text name.
const std::string Name; // Text name of thread descriptor.
ThreadState(std::string N) : Name(N) {} // Constructor requires text name.
}; };


// ThreadType objects are constant static objects defined for each Thread class // ThreadType objects are constant static objects defined for each Thread class


class ThreadType { class ThreadType {
public: public:
const string Name;
ThreadType(string N) : Name(N) {}
const std::string Name;
ThreadType(std::string N) : Name(N) {}
}; };


class Thread; // There is such thing as a Thread. class Thread; // There is such thing as a Thread.
Thread* Pointer; // A pointer to the thread. Thread* Pointer; // A pointer to the thread.
ThreadType* Type; // A descriptor of it's type. ThreadType* Type; // A descriptor of it's type.
ThreadState* State; // A descriptor of it's state. ThreadState* State; // A descriptor of it's state.
string Name; // Name of the thread if any.
std::string Name; // Name of the thread if any.
bool isRunning; // True if the thread is running. bool isRunning; // True if the thread is running.
bool isBad; // True if the thread is bad. bool isBad; // True if the thread is bad.
string Fault; // Bad Thread's Fault if any.
std::string Fault; // Bad Thread's Fault if any.


public: public:
ThreadStatusRecord( // Initialize all items. ThreadStatusRecord( // Initialize all items.
ThreadState& S, ThreadState& S,
bool R, bool R,
bool B, bool B,
string F,
string N
std::string F,
std::string N
) : ) :
Pointer(P), Pointer(P),
Type(&T), Type(&T),
State(&S), State(&S),
Name(N),
Name(N),
isRunning(R), isRunning(R),
isBad(B), isBad(B),
Fault(F) Fault(F)
isRunning = Right.isRunning; isRunning = Right.isRunning;
isBad = Right.isBad; isBad = Right.isBad;
Fault = Right.Fault; Fault = Right.Fault;
Name = Right.Name;
Name = Right.Name;
return *this; return *this;
} }


const ThreadState& getState() { return *State; } const ThreadState& getState() { return *State; }
bool getRunning() { return isRunning; } bool getRunning() { return isRunning; }
bool getBad() { return isBad; } bool getBad() { return isBad; }
string getFault() { return Fault; }
string getName() { return Name; }
std::string getFault() { return Fault; }
std::string getName() { return Name; }
}; };


typedef vector<ThreadStatusRecord> ThreadStatusReport; // Status report type.
typedef std::vector<ThreadStatusRecord> ThreadStatusReport; // Status report type.


// End ThreadDescriptor // End ThreadDescriptor
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////


} // End namespace codedweller

//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Win32 / POSIX abstractions // Win32 / POSIX abstractions


#include <windows.h> #include <windows.h>
#include <process.h> #include <process.h>


namespace codedweller {

typedef HANDLE thread_primative; // The WIN32 thread primative abstracts typedef HANDLE thread_primative; // The WIN32 thread primative abstracts
// HANDLE // HANDLE


SwitchToThread(); // we call SwitchToThread(); SwitchToThread(); // we call SwitchToThread();
} }


} // End namespace codedweller

#else #else


// When in POSIX land... // When in POSIX land...
#include <pthread.h> #include <pthread.h>
#include <sched.h> #include <sched.h>


namespace codedweller {

typedef pthread_t thread_primative; // The POSIX thread primative abstracts typedef pthread_t thread_primative; // The POSIX thread primative abstracts
// pthread_t // pthread_t


sched_yield(); // we call sched_yield(); sched_yield(); // we call sched_yield();
} }


} // End namespace codedweller

#endif #endif


// End Win32 / POSIX abstractions // End Win32 / POSIX abstractions
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////


namespace codedweller {

//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// The Thread class gets extended to do any specific work. The pure virtual // The Thread class gets extended to do any specific work. The pure virtual
// function MyTask is overloaded by the derived class to define that work. It // function MyTask is overloaded by the derived class to define that work. It
protected: protected:


const ThreadType& MyThreadType; // Identify thread type. const ThreadType& MyThreadType; // Identify thread type.
const string MyThreadName; // Name string of this instance.
const std::string MyThreadName; // Name string of this instance.


thread_primative MyThread; // Abstracted thread. thread_primative MyThread; // Abstracted thread.
bool RunningFlag; // True when thread is in myTask() bool RunningFlag; // True when thread is in myTask()
bool BadFlag; // True when myTask() throws! bool BadFlag; // True when myTask() throws!
string BadWhat; // Bad exception what() if any.
std::string BadWhat; // Bad exception what() if any.
void CurrentThreadState(const ThreadState& TS); // Set thread state. void CurrentThreadState(const ThreadState& TS); // Set thread state.


public: public:


Thread(); // Constructor (just in case) Thread(); // Constructor (just in case)
Thread(const ThreadType& T, string N); // Construct with specific Type/Name
Thread(const ThreadType& T, std::string N); // Construct with specific Type/Name
virtual ~Thread(); // Destructor (just in case) virtual ~Thread(); // Destructor (just in case)


void run(); // Method to launch this thread. void run(); // Method to launch this thread.


bool isRunning(); // Return the Running flag state. bool isRunning(); // Return the Running flag state.
bool isBad(); // Return the Bad flag state. bool isBad(); // Return the Bad flag state.
const string MyFault(); // Return exception Bad fault if any.
const std::string MyFault(); // Return exception Bad fault if any.


const string MyName(); // The thread's name.
const std::string MyName(); // The thread's name.
const ThreadType& MyType(); // Thread type for this thread. const ThreadType& MyType(); // Thread type for this thread.
const ThreadState& MyState(); // Returns the current thread state. const ThreadState& MyState(); // Returns the current thread state.
const ThreadState& CurrentThreadState(); // Returns the current thread state. const ThreadState& CurrentThreadState(); // Returns the current thread state.
private: private:


Mutex MyMutex; // Protect our data with this. Mutex MyMutex; // Protect our data with this.
set<Thread*> KnownThreads; // Keep track of all threads.
std::set<Thread*> KnownThreads; // Keep track of all threads.


void rememberThread(Thread* T); // Threads register themselves. void rememberThread(Thread* T); // Threads register themselves.
void forgetThread(Thread* T); // Threads remove themselves. void forgetThread(Thread* T); // Threads remove themselves.


// End Thread Manager // End Thread Manager
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// A ProductionQueue is a templated, thread safe mechanism for implementing
// a producer/consumer relationship. The objects in the queue should be simple
// data so that they can be created, destroyed, and copied without trouble. Put
// another way - the objects in the ProductionQueue should be lightweight
// handles for other things. Those things should be created and destroyed
// elsewhere.
template<typename T> // Templatized
class ProductionQueue { // Production Queue Class
private:
Mutex myMutex; // Contains a mutex and
volatile unsigned int LatestSize; // a volatile (blinking light) size
ProductionGateway myGateway; // integrated with a production
queue<T> myQueue; // gateway and a queue.
public:
ProductionQueue() : LatestSize(0) {} // The size always starts at zero.
T take() { // To consume a queued object
myGateway.consume(); // we wait on the production gateway
ScopeMutex OneAtATimePlease(myMutex); // and when we get through we lock
T O = myQueue.front(); // the mutext, take the object on the
myQueue.pop(); // front of the queue, pop it out,
LatestSize = myQueue.size(); // and rest our size (blinking light).
return O; // Then return the object we got.
}
void give(T O) { // To produce a queued object
ScopeMutex OneAtATimePlease(myMutex); // we wait on the mutex. When we
myQueue.push(O); // get through we push our object
LatestSize = myQueue.size(); // into the queue, reset our size
myGateway.produce(); // indicator and tell the gateway.
} // When we're done it can be grabbed.
unsigned int size() { // To check the size we look at
return LatestSize; // the blinking light.
}
};
// End Production Queue
////////////////////////////////////////////////////////////////////////////////


#endif
////////////////////////////////////////////////////////////////////////////////
// A ProductionQueue is a templated, thread safe mechanism for implementing
// a producer/consumer relationship. The objects in the queue should be simple
// data so that they can be created, destroyed, and copied without trouble. Put
// another way - the objects in the ProductionQueue should be lightweight
// handles for other things. Those things should be created and destroyed
// elsewhere.

template<typename T> // Templatized
class ProductionQueue { // Production Queue Class
private:
Mutex myMutex; // Contains a mutex and
volatile unsigned int LatestSize; // a volatile (blinking light) size
ProductionGateway myGateway; // integrated with a production
std::queue<T> myQueue; // gateway and a queue.

public:
ProductionQueue() : LatestSize(0) {} // The size always starts at zero.

T take() { // To consume a queued object
myGateway.consume(); // we wait on the production gateway
ScopeMutex OneAtATimePlease(myMutex); // and when we get through we lock
T O = myQueue.front(); // the mutext, take the object on the
myQueue.pop(); // front of the queue, pop it out,
LatestSize = myQueue.size(); // and rest our size (blinking light).
return O; // Then return the object we got.
}

void give(T O) { // To produce a queued object
ScopeMutex OneAtATimePlease(myMutex); // we wait on the mutex. When we
myQueue.push(O); // get through we push our object
LatestSize = myQueue.size(); // into the queue, reset our size
myGateway.produce(); // indicator and tell the gateway.
} // When we're done it can be grabbed.

unsigned int size() { // To check the size we look at
return LatestSize; // the blinking light.
}
};

// End Production Queue
////////////////////////////////////////////////////////////////////////////////


// End Of Include MNR_threading Once Only ======================================
} // End namespace codedweller

+ 8
- 25
timing.cpp 查看文件

// timing.cpp // timing.cpp
// //
// Copyright (C) 2006 - 2009 MicroNeil Research Corporation.
// Copyright (C) 2004-2020 MicroNeil Research Corporation.
// //
// See the corresponding .hpp file for descriptions and history.
//
// This program is part of the MicroNeil Research Open Library Project. For
// more information go to http://www.microneil.com/OpenLibrary/index.html
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 2 of the License, or (at your
// option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along with
// this program; if not, write to the Free Software Foundation, Inc., 59 Temple
// Place, Suite 330, Boston, MA 02111-1307 USA
// This software is released under the MIT license. See LICENSE.TXT.


#include <ctime> #include <ctime>
#include <sys/time.h> #include <sys/time.h>


#include "timing.hpp" #include "timing.hpp"


// Introduce the standard namespace ////////////////////////////////////////////

using namespace std;
namespace codedweller {


/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// class Sleeper - An object that remembers how long it is supposed to sleep. // class Sleeper - An object that remembers how long it is supposed to sleep.
if(x < MinimumSleeperTime || if(x < MinimumSleeperTime ||
x > MaximumSleeperTime) // If it's not a good time value x > MaximumSleeperTime) // If it's not a good time value
throw BadSleeperValue(); // then throw the exception. throw BadSleeperValue(); // then throw the exception.
MillisecondsToSleep = x; // If it is good - set it.
MillisecondsToSleep = x; // If it is good - set it.
return MillisecondsToSleep; // Return the set value. return MillisecondsToSleep; // Return the set value.
} }


// a natural spiral. // a natural spiral.
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////


PollTimer::PollTimer(int Nom, int Max) :
NominalPollTime(MinimumSleeperTime),
PollTimer::PollTimer(int Nom, int Max) :
NominalPollTime(MinimumSleeperTime),
MaximumPollTime(MinimumSleeperTime) { // Construction requires a MaximumPollTime(MinimumSleeperTime) { // Construction requires a
setNominalPollTime(Nom); // nominal delay to use and setNominalPollTime(Nom); // nominal delay to use and
setMaximumPollTime(Max); // a maximum delay to allow. setMaximumPollTime(Max); // a maximum delay to allow.
bool Timeout::isExpired() { // Return true if time is up. bool Timeout::isExpired() { // Return true if time is up.
return (!(myTimer.getElapsedTime() < myDuration)); // Check the elapsed time against myDuration. return (!(myTimer.getElapsedTime() < myDuration)); // Check the elapsed time against myDuration.
} }

} // End namespace codedweller

+ 6
- 51
timing.hpp 查看文件

// timing.hpp // timing.hpp
// //
// Copyright (C) 2004-2009 MicroNeil Research Corporation.

// This program is part of the MicroNeil Research Open Library Project. For
// more information go to http://www.microneil.com/OpenLibrary/index.html
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 2 of the License, or (at your
// option) any later version.
// Copyright (C) 2004-2020 MicroNeil Research Corporation.
// //
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
// This software is released under the MIT license. See LICENSE.TXT.
// //
// You should have received a copy of the GNU General Public License along with
// this program; if not, write to the Free Software Foundation, Inc., 59 Temple
// Place, Suite 330, Boston, MA 02111-1307 USA

// The purpose of this module is to abstract timing functions for // The purpose of this module is to abstract timing functions for
// cross platform C++ development usning GNU compilers in *nix and // cross platform C++ development usning GNU compilers in *nix and
// win32 environments (minGW). Timing resolution is in milliseconds // win32 environments (minGW). Timing resolution is in milliseconds
// throughout to provide consistency and reasonable expectations. // throughout to provide consistency and reasonable expectations.


// 20060404 _M Added Timer::start(msclock startt) for chaining.

// 20060403 _M This "timing" module has been completed and tested on
// win32 (compiled using CodeBlocks and minGW) and on RHES3 (g++).
//
// The bottom line is that this code is perfect for most applications that
// don't need real-time interaction on the win32 platform. That is, for
// any application that can accept 15ms or so of "wiggle" in their timing
// functions. On linux I was able to observe very consistent results with
// variations measured in 1-2ms.
//
// Aynone seeking real-time accuracy on the win32 platform will need to contend
// with all of the landmines in place against that and will need to write more
// ellaborate versions of Timer::getLocalRawClock() and Sleeper::doRawSleep()
// aa appropriate for their application. The existing code should work fine for
// almost all other applications.
//
// This code was written with that in mind to some extent. That is why all of
// the timing functions are measured in milliseconds rather than microseconds
// or something smaller. Milliseconds are convenient for polling delays,
// communications timeouts, measuring database application performance, and
// other similar tasks. For that purpose - this timing module is just fine :-)

// 20060323 _M Rewrote this module from a combination of previous
// bits and pieces. This module will provide classes that abstract
// timing functions for use in GNU projects on *nix and win32 systems.

#ifndef MNR_timing
#define MNR_timing

// Introduce the standard namespace ///////////////////////////////////////////
#pragma once


using namespace std;
namespace codedweller {


/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// class Sleeper - An object that remembers how long it is supposed to sleep. // class Sleeper - An object that remembers how long it is supposed to sleep.


private: private:


bool RunningFlag; // True if clock is running.
bool RunningFlag; // True if clock is running.
msclock StartTime; // TimeOfDay at start. msclock StartTime; // TimeOfDay at start.
msclock StopTime; // TimeOfDay at stop or check. msclock StopTime; // TimeOfDay at stop or check.


** Returns true if time is up. ** Returns true if time is up.
*/ */


#endif // End MNR_timing once-only switch.
} // End namespace codedweller

正在加载...
取消
保存