Thread: [Fftrader-cvs] fftrader3d/src/common aries.cpp,NONE,1.1 aries.h,NONE,1.1 config.cpp,NONE,1.1 config.
Status: Alpha
Brought to you by:
tomt64
Update of /cvsroot/fftrader/fftrader3d/src/common In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv6521/src/common Added Files: aries.cpp aries.h config.cpp config.h console.cpp console.h datalib.h log.cpp log.h Log Message: Initial checkin --- NEW FILE: config.h --- #ifndef CONFIG_H #define CONFIG_H #include <string> #include <map> class ConfigFile { private: std::map<std::string, std::string> keyMap; public: void addKey(const char* keyName, const char* keyValue); void delKey(const char* keyName); void loadConfig(const char* fileName); void saveConfig(const char* fileName); std::string operator [](const std::string& keyName); int getKey (const std::string& keyName); }; #endif --- NEW FILE: config.cpp --- #include "config.h" #include <fstream> void ConfigFile::addKey(const char* keyName, const char* keyValue) { keyMap[keyName] = keyValue; } void ConfigFile::delKey(const char* keyName) { } int ConfigFile::getKey(const std::string& keyName) { return atoi(keyMap[keyName].c_str()); } void ConfigFile::loadConfig(const char* fileName) { std::string key, value; std::ifstream configFile(fileName); while(configFile) { configFile >> key >> value; addKey(key.c_str(), value.c_str()); } } void ConfigFile::saveConfig(const char* fileName) { } std::string ConfigFile::operator [](const std::string& keyName) { std::map<std::string, std::string>::iterator i = keyMap.find(keyName); if (i == keyMap.end()) return ""; return i->second; } --- NEW FILE: console.h --- #ifndef CONSOLE_H #define CONSOLE_H #include <string> #include <vector> #include <list> #include <iostream> enum t_consoleType { CTYPE_INT, CTYPE_CHAR, CTYPE_FLOAT, CTYPE_STRING, CTYPE_FUNCTION }; typedef void (*t_consoleFunction)(const std::vector<std::string> &); typedef struct t_consoleItem { std::string name; t_consoleType type; union { void *varPtr; t_consoleFunction function; }; }; class Console { public: void addItem(const std::string &itemName, void *itemPtr, t_consoleType itemType); void delItem(const std::string &itemName); void print(const std::string &lineText); virtual void render() = 0; void parseCmdLine(); private: std::list<t_consoleItem> itemList; std::string cmdLine; protected: std::list<std::string> lineBuffer; }; #endif --- NEW FILE: aries.cpp --- #include "aries.h" #include <iostream> #include <fstream> #include <sstream> #include <stack> #include <cassert> #include <stdexcept> namespace aries { // Helper functions for the parser bool isWhiteSpace(char c) { return c==' ' || c=='\t' || c=='\n' || c=='\r'; //static const std::string whiteSpace(" \t\n\r"); //return whiteSpace.find(c) != std::string::npos; } std::string readIdentifier(std::istream& stream) { std::stringstream ss; do { char c = stream.peek(); if (isWhiteSpace(c) || !stream.good()) break; stream.get(); ss << c; } while (true); return ss.str(); } void eatWhiteSpace(std::istream& stream) { // C++ badly needs a // do { ... } while (condition) { ... } // construct. do { char c = stream.peek(); if (isWhiteSpace(c) || !stream.good()) break; stream.get(); } while (1); } // Removes all leading and trailing whitespace from the string. std::string stripString(const std::string& str) { uint start = 0; uint end = str.length(); while (isWhiteSpace(str[start]) && start < str.length()) start++; while (isWhiteSpace(str[end - 1]) && end > 0) end--; if (start >= end) return ""; else return str.substr(start, end - start); } DataNode* Node::readDocument(std::istream& stream) { std::stack<DataNode*> docStack; // I don't want to recurse for some reason, so I keep the context in an explicit stack. DataNode* rootNode = new DataNode("root"); docStack.push(rootNode); /* * Read a character. * If it's not an opening parenth, then grab characters until we get to a parenth, and pack it into a single StringNode. * If it is, then grab characters up until a space, then create a new DataNode, and parse its children. * If it is a closing parenth, then the node is complete. We resume parsing its parent. */ while (stream.good()) { assert(docStack.size() >= 1); char c = stream.get(); if (c == '(') { std::string nodeName = stripString(readIdentifier(stream)); DataNode* newNode = new DataNode(nodeName); docStack.top()->addChild(newNode); docStack.push(newNode); } else if (c == ')') { // the root node is 1, and you may not actually terminate that node, as it is implicit, and not part // of the document itself. if (docStack.size() < 2) throw std::runtime_error("Malformed markup document"); docStack.pop(); } else { std::stringstream ss; while (c != '(' && c != ')' && stream.good()) { ss << c; c = stream.get(); } stream.unget(); std::string s = stripString(ss.str()); if (s.length()) docStack.top()->addChild(s); } } return rootNode; } //------------------------------------------------------------------------- StringNode::StringNode(const std::string& str) : _str(str) {} bool StringNode::isString() const { return true; } std::string StringNode::toString() const { return _str; } Node* StringNode::clone() const { return new StringNode(_str); } std::ostream& StringNode::write(std::ostream& stream) const { stream << _str; return stream; } //------------------------------------------------------------------------- DataNode::DataNode(const std::string& name) : _name(name) {} DataNode::~DataNode() { for (uint i = 0; i < _children.size(); i++) delete _children[i]; } bool DataNode::isString() const { return false; } std::string DataNode::toString() const { std::stringstream ss; write(ss, 0); return ss.str(); } Node* DataNode::clone() const { DataNode* newNode = new DataNode(_name); for (uint i = 0; i < _children.size(); i++) { newNode->addChild(*_children[i]); } return newNode; } std::string DataNode::getString() const { for (unsigned int i = 0; i < _children.size(); i++) { if (_children[i]->isString()) return _children[i]->toString(); } return ""; } const NodeList& DataNode::getChildren() const { return _children; } NodeList& DataNode::getChildren() { return _children; } DataNodeList DataNode::getChildren(const std::string& name) const { DataNodeList list; for (NodeList::const_iterator i = _children.begin(); i != _children.end(); i++) { Node* n = *i; if (!n->isString() && reinterpret_cast<DataNode*>(n)->getName() == name) list.push_back(reinterpret_cast<DataNode*>(n)); } return list; } DataNode* DataNode::getChild(const std::string& name) const { DataNode* n = getChild(name, 0); if (!n) throw std::runtime_error(std::string("Unable to find node ") + name); else return n; /*for (NodeList::const_iterator i = _children.begin(); i != _children.end(); i++) { Node* n = *i; if (!n->isString() && reinterpret_cast<DataNode*>(n)->getName() == name) return reinterpret_cast<DataNode*>(n); } throw std::runtime_error(std::string("Unable to find node ") + name);*/ } DataNode* DataNode::getChild(const std::string& name, DataNode* defaultValue) const { for (NodeList::const_iterator i = _children.begin(); i != _children.end(); i++) { Node* n = *i; if (!n->isString() && reinterpret_cast<DataNode*>(n)->getName() == name) return reinterpret_cast<DataNode*>(n); } return defaultValue; } bool DataNode::hasChild(const std::string& name) const { for (NodeList::const_iterator i = _children.begin(); i != _children.end(); i++) { Node* n = *i; if (!n->isString() && reinterpret_cast<DataNode*>(n)->getName() == name) return true; } return false; } std::string DataNode::getName() const { return _name; } DataNode* DataNode::addChild(const std::string& str) { return addChild(new StringNode(str)); } DataNode* DataNode::addChild(int n) { char c[32]; sprintf(c, "%i", n); return addChild(std::string(c)); } /*DataNode* DataNode::addChild(double d) { char c[32]; sprintf(c, "%d", d); return addChild(std::string(c)); }*/ DataNode* DataNode::addChild(Node* n) { _children.push_back(n); return this; } DataNode* DataNode::addChild(const Node& n) { _children.push_back(n.clone()); return this; } std::ostream& DataNode::write(std::ostream& stream) const { write(stream, 0); return stream; } void DataNode::write(std::ostream& stream, uint indentLevel) const { indentLevel += 1; stream << "(" << _name << " "; if (_children.size() == 1 && _children[0]->isString()) { // When there's just one string node, no newlines. It's ugly looking. stream << _children[0]->toString() << ")"; } else { for (uint i = 0; i < _children.size(); i++) { stream << "\n"; stream << std::string(indentLevel, '\t'); if (_children[i]->isString()) stream << _children[i]->toString(); else reinterpret_cast<DataNode*>(_children[i])->write(stream, indentLevel); } stream << "\n"; stream << std::string(indentLevel - 1, '\t'); stream << ")"; } } void unittest() { aries::DataNode* root = new aries::DataNode("root"); root->addChild(aries::StringNode("wee!")) ->addChild( aries::newNode("child") ->addChild("String data!") ) ->addChild( aries::newNode("child2") ->addChild( aries::newNode("child3") ->addChild("nesting!") ->addChild("This is so hot.") ) ) ->addChild("FEEL THE BURN"); std::stringstream ss; ss << root; std::cout << ss.str() << std::endl; aries::DataNode* n = aries::Node::readDocument(ss); std::cout << n << std::endl; delete root; delete n; } DataNode* newNode(const std::string& str) { return new DataNode(str); } } std::ostream& operator << (std::ostream& stream, aries::Node* node) { node->write(stream); return stream; } std::istream& operator >> (std::istream& stream, aries::DataNode*& node) { node = aries::Node::readDocument(stream); return stream; } --- NEW FILE: aries.h --- /** * Aries - The simplest markup language ever made. * Coded by Andy Friesen. * * Pseudo-BNF because I don't recall how BNF works exactly: * * Node :== string | (nodeName OneOrMoreNodes) * * Look like lisp? Guess what inspired it. * Extremely easy to parse, extremely easy to read. * Much less verbose than XML as well, though the lack of an analogue to * attributes makes automated conversion more or less impossible. * * Text is brought into the markup literally, with only leading and trailing * whitespace removed. (of course, you could always cut it up into tokens * yourself) Thus, if exact whitespace is important to you, just enclose the * datum in quotes. (or anything that's not parenthesis, really) * * Gay little example from an alternate dimension where HTML has been turned * into an Aries-based markup: * * (html * (head * (title tSBUPoNiP) * ) * (body * (font (size 3)(bold (underline * News * (-- Note that this markup has no comment system. Thus, we agree to * ignore all nodes that are named "--". Voila. Comments. ^_^ * * Note that comments can nest, due to the fact that they're not * really comments at all. I do have misgivings about forcing * comments to balance parenths, though. Maybe comments should be * added to the spec. * ) * ))) * (p * (bold (underline October 20)) * (br) Minor update. * (ul * (li v2 8 bit fonts added. v2.7 will (italics always) assume they * use v2's default palette; if they do not, you will have to * convert them to something else first. ) * (li major optimization concerning WinMapEd's image import feature. * The speed increase should be considerable. ) * (li v2.7 now uses (a (href http://www.python.org) Python 2.2). This * has a number of exceptional new language features. I highly * reccomend that you check the official site to see what's new. ) * ) * ) * ) */ /* * Legal garbage: * * Copyright (c) 2003 Andy Friesen * * This software is provided 'as-is', without any express or implied warranty. * In no event will the authors be held liable for any damages arising from * the use of this software. * * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * * 2. Altered source versions must be plainly marked as such, and must not * be misrepresented as being the original software. * * 3. This notice may not be removed or altered from any source distribution. * */ // Source modified to compile in VC6 // -TomT64 #ifndef ARIES_H #define ARIES_H #include <string> #include <vector> namespace aries { typedef unsigned int uint; typedef std::vector<struct Node*> NodeList; typedef std::vector<struct DataNode*> DataNodeList; /** * Base class for all document nodes. * (there are only two anyway) */ struct Node { virtual ~Node(){} /** * Basically required so that RTTI doesn't need to be enabled. Returns true if the node * is a StringNode, false if it is a DataNode */ virtual bool isString() const = 0; /** * Returns a string representation of the node. */ virtual std::string toString() const = 0; /** * Creates a clone of the node, and returns it. The caller assumes ownership of the new node. */ virtual Node* clone() const = 0; /** * Writes the node to the stream. * The overloaded << operator calls this. */ virtual std::ostream& write(std::ostream& stream) const = 0; /** * Reads a document from the stream, and returns a node containing the document. * Note that, if you have a single root in your document, a la XML, that it will * be the only child of the node returned. * * operator >> calls this. */ static struct DataNode* readDocument(std::istream& stream); }; struct StringNode : Node { StringNode(const std::string& str); virtual bool isString() const; virtual std::string toString() const; virtual Node* clone() const; virtual std::ostream& write(std::ostream& stream) const; private: std::string _str; }; struct DataNode : Node { DataNode(const std::string& name); virtual ~DataNode(); virtual bool isString() const; virtual std::string toString() const; virtual Node* clone() const; std::string getString() const; ///< Returns the string data of the first string node, or "" if there isn't one. NodeList& getChildren(); ///< Returns a list of the children const NodeList& getChildren() const; ///< ditto DataNodeList getChildren(const std::string& name) const; ///< Returns all data nodes with the specified node name DataNode* getChild(const std::string& name) const; ///< Returns the first data node with the specified name. Throws a std::runtime_error if the child does not exist. DataNode* getChild(const std::string& name, DataNode* defaultValue) const; ///< Returns the first data node with the specified name, or defaultValue if the node cannot be found. bool hasChild(const std::string& name) const; ///< Returns true if the node has a child by this name. std::string getName() const; ///< Returns the name of the node DataNode* addChild(const std::string& str); ///< Creates a StringNode and adds it as a new child DataNode* addChild(int i); //DataNode* addChild(double d); DataNode* addChild(const Node& n); ///< Adds a copy of the node as a child DataNode* addChild(Node* n); ///< Adds the node as a child. The node assumes ownership of the pointer. (so don't delete it yourself) virtual std::ostream& write(std::ostream& stream) const; private: void write(std::ostream& stream, unsigned int indentLevel = 0) const; NodeList _children; std::string _name; }; void unittest(); ///< Pretty crappy unit test, but it's better than nothing. /** * since VC7 does not consider new DataNode(...)->addChild(...) to be valid C++, * You'll have to either put parenths around it, or use this. */ DataNode* newNode(const std::string& str); } std::ostream& operator << (std::ostream& stream, aries::Node* node); /// Converts the node (and its children) to a human readable format, and dumps it to the stream. std::istream& operator >> (std::istream& stream, aries::DataNode*& node); /// Reads the document in from the stream, and returns the root node. The caller assumes ownership of the pointer. #endif --- NEW FILE: log.cpp --- #include "log.h" #include <stdarg.h> #include <ios> #include <stdio.h> using std::endl; namespace Log { bool logInit = false; std::ofstream logFile; }; void Log::Init(const char *fileName) { if (logInit) return; logInit = true; logFile.open(fileName); } void Log::Write(const char* logText) { if (!logInit) return; logFile << logText; } void Log::Write(const std::string& logText) { if (!logInit) return; logFile << logText; } --- NEW FILE: log.h --- #ifndef LOG_H #define LOG_H #include <fstream> namespace Log { void Init(const char* fileName); void Write(const char* logText); void Write(const std::string& logText); }; #endif --- NEW FILE: datalib.h --- #ifndef DATALIB_H #define DATALIB_H #include <vector> #include <iostream> //Debug using namespace std; template <class T> class DataLib { private: std::vector<std::string> nameList; std::vector<T*> dataList; public: DataLib() {}; ~DataLib(); T* load(const char* Name); }; template<class T> DataLib<T>::~DataLib() { // cout << "DataLib Deconstructor" << "\t" << dataList.size() << "\t" << nameList.size() << "\t" << this << endl; typename vector<T*>::iterator i; for(i = dataList.begin(); i != dataList.end(); i++) { delete *i; } } template<class T> T* DataLib<T>::load(const char* fileName) { for(int i=0; i<nameList.size(); i++) { if (fileName == nameList[i]) { // cout << fileName << " == " << nameList[i] << "\t - Returning Addr: " << &dataList[i] << endl; return dataList[i]; } } T *newData = new T(fileName); nameList.push_back(fileName); dataList.push_back(newData); // cout << fileName << " != " << nameList[nameList.size() - 1] << "\t - Returning Addr: " << &dataList[dataList.size() - 1] << endl; return dataList[dataList.size() - 1]; } #endif --- NEW FILE: console.cpp --- #include "console.h" #include <iostream> using namespace std; void Console::addItem(const std::string &itemName, void *itemPtr, t_consoleType itemType) { t_consoleItem newItem; newItem.name = itemName; newItem.type = itemType; if(itemType == CTYPE_FUNCTION) newItem.function = (t_consoleFunction)itemPtr; else newItem.varPtr = itemPtr; itemList.push_back(newItem); } void Console::delItem(const std::string &itemName) { std::list<t_consoleItem>::iterator iter; for(iter = itemList.begin(); iter != itemList.end(); iter++) { if(iter->name == itemName) { itemList.erase(iter); return; } } } void Console::parseCmdLine() { std::vector<std::string> arguments; //Tokenize the son of a .... std::string::size_type lastPos = cmdLine.find_first_not_of(" ", 0); std::string::size_type index = cmdLine.find_first_of(" ", lastPos); while(index != std::string::npos || std::string::npos != lastPos) { arguments.push_back(cmdLine.substr(lastPos, index - lastPos)); lastPos = cmdLine.find_first_not_of(" ", index); index = cmdLine.find_first_of(" ", lastPos); } //What to do.. what to do... std::list<t_consoleItem>::iterator iter; for(iter = itemList.begin(); iter != itemList.end(); iter++) { if(iter->name == arguments[0]) { switch(iter->type) { case CTYPE_INT: if(arguments.size() > 2) return; else if(arguments.size() == 2) *((int*)(*iter).varPtr) = (int)atoi(arguments[1].c_str()); // std::ostringstream ss; // ss << (*iter).name << " = " << *((int*)(*iter).varPtr) << endl; lineBuffer.push_back("BOOP"); break; case CTYPE_FUNCTION: (*iter).function(arguments); break; } return; } } //Didn't find anything to do, blame the user. std::cout << "Error: not variable or command '" << cmdLine << "'" << std::endl; } |