You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

223 lines
5.6 KiB

#ifndef FML_H
#define FML_H
#include <sstream>
#include <string>
#include <vector>
#include <iterator>
#include <map>
#include <boost/utility.hpp>
#include <boost/foreach.hpp>
namespace FML {
///////////////////////////////////////////////////////////////////////////////
// Utilities
bool fml_convert(const std::string& input, bool& b);
bool fml_convert(const std::string& input, std::string& output);
template <typename V, typename T>
bool fml_convert(const V& in, T& out) {
std::stringstream ss;
ss << in;
ss >> out;
return !!ss;
}
///////////////////////////////////////////////////////////////////////////////
// Node
class Parser;
class Node : boost::noncopyable
{
public:
typedef std::vector<Node*> NodeList;
Node(Parser* parser = 0) : m_parser(parser), m_parent(0), m_line(0) { }
~Node();
bool hasTag() const { return !m_tag.empty(); }
bool hasChildren() const { return size() > 0; }
bool hasValue() const { return !m_value.empty(); }
bool hasNode(const std::string childTag) const { return at(childTag) != 0; }
void setTag(std::string tag) { m_tag = tag; }
void setLine(int line) { m_line = line; }
void setValue(const std::string& value) { m_value = value; }
void setParent(Node* parent) { m_parent = parent; }
std::string tag() const { return m_tag; }
int line() const { return m_line; }
int size() const { return m_children.size(); }
Node* parent() { return m_parent; }
// iterators
typedef NodeList::iterator iterator;
typedef NodeList::const_iterator const_iterator;
iterator begin() { return m_children.begin(); }
iterator end() { return m_children.end(); }
const_iterator begin() const { return m_children.begin(); }
const_iterator end() const { return m_children.end(); }
Node* front() const { return at(0); }
Node* back() const { return at(size()-1); }
// util for generating error message
std::string generateErrorMessage(const std::string& message) const;
// extracting values operator
template <typename T>
friend bool operator >> (const Node& node, T& value);
// get nodes
Node* at(const std::string& childTag) const;
Node* at(int pos) const;
// get values
std::string value(const std::string& def = std::string()) const;
std::string valueAt(const std::string childTag, const std::string& def = std::string()) const;
// read values
template <typename T>
T read(T def = T()) const {
T v = def;
*this >> v;
return v;
}
template <typename T>
bool read(T* v) const {
return (*this >> *v);
}
template <typename T>
T readAt(const std::string& childTag, T def = T()) const {
T v = def;
for(NodeList::const_iterator it = m_children.begin(); it != m_children.end(); ++it) {
if((*it)->tag() == childTag) {
*(*it) >> v;
break;
}
}
return v;
}
template <typename T>
bool readAt(const std::string& childTag, T* v) const {
for(NodeList::const_iterator it = m_children.begin(); it != m_children.end(); ++it) {
if((*it)->tag() == childTag)
return (*(*it) >> *v);
}
return false;
}
void addNode(Node* node);
private:
Parser* m_parser;
Node* m_parent;
int m_line;
NodeList m_children;
std::string m_tag;
std::string m_value;
};
///////////////////////////////////////////////////////////////////////////////
// Node operators
template <typename T>
bool operator >> (const Node& node, T& v)
{
return fml_convert(node.value(), v);
}
template <typename T>
bool operator >> (const Node& node, std::vector<T>& v)
{
bool ret = true;
v.clear();
v.resize(node.size());
for(unsigned i=0;i<node.size();++i) {
if(!(*node.at(i) >> v[i]))
ret = false;
}
return ret;
}
template <typename K, typename T>
bool operator >> (const Node& node, std::map<K, T>& m)
{
bool ret = true;
m.clear();
for(Node::const_iterator it = node.begin(); it != node.end(); ++it) {
Node* child = (*it);
K k;
T v;
if(fml_convert<std::string, K>(child->tag(), k)) {
*child >> v;
m[k] = v;
ret = false;
}
}
return ret;
}
///////////////////////////////////////////////////////////////////////////////
// Parser
class Parser
{
enum MultilineMode {
DONT_MULTILINE = 0,
MULTILINE_DONT_FOLD,
MULTILINE_FOLD_BLOCK,
MULTILINE_FOLD_FLOW
};
public:
Parser(std::string what = std::string()) : m_rootNode(0), m_what(what) { }
Parser(std::istream& in, std::string what = std::string()) : m_rootNode(0), m_what(what) { load(in); }
~Parser();
bool load(std::istream& in);
Node* getDocument() const { return m_rootNode; }
bool hasError() const { return !m_error.empty(); }
std::string getErrorMessage() { return m_error; }
std::string getWhat() { return m_what; }
protected:
void parseLine(std::string& line);
Node* parseNode(std::string& line);
std::string parseTextScalar(std::string value);
void startMultilining(const std::string& param);
void stopMultilining();
bool parseMultiline(std::string line);
bool isMultilining() { return m_multilineMode != DONT_MULTILINE; }
void setErrorMessage(const std::string& message, int line = 0);
private:
int m_currentDepth;
int m_currentLine;
Node* m_currentParent;
Node* m_previousNode;
Node* m_rootNode;
MultilineMode m_multilineMode;
std::string m_multilineData;
std::string m_error;
std::string m_what;
};
} // namespace FML {
#endif // FML_H