summaryrefslogtreecommitdiff
path: root/src/xml.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/xml.h')
-rw-r--r--src/xml.h423
1 files changed, 423 insertions, 0 deletions
diff --git a/src/xml.h b/src/xml.h
new file mode 100644
index 00000000..6a600786
--- /dev/null
+++ b/src/xml.h
@@ -0,0 +1,423 @@
+#ifndef _XML_H
+#define _XML_H
+
+#include "value.h"
+#include "parser.h"
+
+namespace ledger {
+
+class transaction_t;
+class entry_t;
+class account_t;
+class journal_t;
+
+namespace xml {
+
+#define XML_NODE_IS_PARENT 0x1
+
+DECLARE_EXCEPTION(conversion_exception);
+
+class parent_node_t;
+class document_t;
+
+class node_t
+{
+public:
+ unsigned int name_id;
+#ifdef THREADSAFE
+ document_t * document;
+#else
+ static document_t * document;
+#endif
+ parent_node_t * parent;
+ node_t * next;
+ node_t * prev;
+ unsigned int flags;
+
+ typedef std::map<string, string> attrs_map;
+ typedef std::pair<string, string> attrs_pair;
+
+ attrs_map * attrs;
+
+ node_t(document_t * _document, parent_node_t * _parent = NULL,
+ unsigned int _flags = 0);
+
+ virtual ~node_t() {
+ TRACE_DTOR(node_t);
+ if (parent) extract();
+ if (attrs) delete attrs;
+ }
+
+ void extract(); // extract this node from its parent's child list
+
+ virtual const char * text() const {
+ assert(0);
+ return NULL;
+ }
+
+ const char * name() const;
+ int set_name(const char * _name);
+ int set_name(int _name_id) {
+ name_id = _name_id;
+ return name_id;
+ }
+
+ void set_attr(const char * n, const char * v) {
+ if (! attrs)
+ attrs = new attrs_map;
+ std::pair<attrs_map::iterator, bool> result =
+ attrs->insert(attrs_pair(n, v));
+ assert(result.second);
+ }
+ const char * get_attr(const char * n) {
+ if (attrs) {
+ attrs_map::iterator i = attrs->find(n);
+ if (i != attrs->end())
+ return (*i).second.c_str();
+ }
+ return NULL;
+ }
+
+ node_t * lookup_child(const char * _name) const;
+ node_t * lookup_child(const string& _name) const;
+ virtual node_t * lookup_child(int /* _name_id */) const {
+ return NULL;
+ }
+
+ virtual value_t to_value() const {
+ throw_(conversion_exception, "Cannot convert node to a value");
+ }
+
+ virtual void write(std::ostream& out, int depth = 0) const = 0;
+
+private:
+ node_t(const node_t&);
+ node_t& operator=(const node_t&);
+};
+
+class parent_node_t : public node_t
+{
+public:
+ mutable node_t * _children;
+ mutable node_t * _last_child;
+
+ parent_node_t(document_t * _document, parent_node_t * _parent = NULL)
+ : node_t(_document, _parent, XML_NODE_IS_PARENT),
+ _children(NULL), _last_child(NULL)
+ {
+ TRACE_CTOR(parent_node_t, "document_t *, parent_node_t *");
+ }
+ virtual ~parent_node_t() {
+ TRACE_DTOR(parent_node_t);
+ if (_children) clear();
+ }
+
+ virtual void clear(); // clear out all child nodes
+ virtual node_t * children() const {
+ return _children;
+ }
+ virtual node_t * last_child() {
+ if (! _children)
+ children();
+ return _last_child;
+ }
+ virtual void add_child(node_t * node);
+
+ void write(std::ostream& out, int depth = 0) const;
+
+private:
+ parent_node_t(const parent_node_t&);
+ parent_node_t& operator=(const parent_node_t&);
+};
+
+class terminal_node_t : public node_t
+{
+ string data;
+
+public:
+ terminal_node_t(document_t * _document, parent_node_t * _parent = NULL)
+ : node_t(_document, _parent)
+ {
+ TRACE_CTOR(terminal_node_t, "document_t *, parent_node_t *");
+ }
+ virtual ~terminal_node_t() {
+ TRACE_DTOR(terminal_node_t);
+ }
+
+ virtual const char * text() const {
+ return data.c_str();
+ }
+ virtual void set_text(const char * _data) {
+ data = _data;
+ }
+ virtual void set_text(const string& _data) {
+ data = _data;
+ }
+
+ virtual value_t to_value() const {
+ return text();
+ }
+
+ void write(std::ostream& out, int depth = 0) const;
+
+private:
+ terminal_node_t(const node_t&);
+ terminal_node_t& operator=(const node_t&);
+};
+
+class document_t
+{
+ static const char * ledger_builtins[];
+ static const std::size_t ledger_builtins_size;
+
+public:
+ enum ledger_builtins_t {
+ ACCOUNT = 10,
+ ACCOUNT_PATH,
+ AMOUNT,
+ CODE,
+ COMMODITY,
+ ENTRIES,
+ ENTRY,
+ JOURNAL,
+ NAME,
+ NOTE,
+ PAYEE,
+ TRANSACTION
+ };
+
+private:
+ typedef std::vector<string> names_array;
+
+ names_array names;
+
+ typedef std::map<string, int> names_map;
+ typedef std::pair<string, int> names_pair;
+
+ names_map names_index;
+
+ terminal_node_t stub;
+
+ public:
+ node_t * top;
+
+ // Ids 0-9 are reserved. 10-999 are for "builtin" names. 1000+ are
+ // for dynamically registered names.
+ enum special_names_t {
+ CURRENT, PARENT, ROOT, ALL
+ };
+
+ document_t(node_t * _top = NULL);
+ ~document_t();
+
+ void set_top(node_t * _top);
+
+ int register_name(const string& name);
+ int lookup_name_id(const string& name) const;
+ static int lookup_builtin_id(const string& name);
+ const char * lookup_name(int id) const;
+
+ void write(std::ostream& out) const;
+
+#if defined(HAVE_EXPAT) || defined(HAVE_XMLPARSE)
+ class parser_t
+ {
+ public:
+ document_t * document;
+ XML_Parser parser;
+ string have_error;
+ const char * pending;
+ node_t::attrs_map * pending_attrs;
+ bool handled_data;
+
+ std::list<parent_node_t *> node_stack;
+
+ parser_t() : document(NULL), pending(NULL), pending_attrs(NULL),
+ handled_data(false) {}
+ virtual ~parser_t() {}
+
+ virtual bool test(std::istream& in) const;
+ virtual document_t * parse(std::istream& in);
+ };
+#endif
+};
+
+#if defined(HAVE_EXPAT) || defined(HAVE_XMLPARSE)
+
+class xml_parser_t : public parser_t
+{
+ public:
+ virtual bool test(std::istream& in) const;
+
+ virtual unsigned int parse(std::istream& in,
+ journal_t * journal,
+ account_t * master = NULL,
+ const string * original_file = NULL);
+};
+
+DECLARE_EXCEPTION(parse_exception);
+
+#endif
+
+class commodity_node_t : public parent_node_t
+{
+public:
+ commodity_t * commodity;
+
+ commodity_node_t(document_t * _document,
+ commodity_t * _commodity,
+ parent_node_t * _parent = NULL)
+ : parent_node_t(_document, _parent), commodity(_commodity) {
+ TRACE_CTOR(commodity_node_t, "document_t *, commodity_t *, parent_node_t *");
+ set_name(document_t::COMMODITY);
+ }
+ virtual ~commodity_node_t() {
+ TRACE_DTOR(commodity_node_t);
+ }
+
+ virtual node_t * children() const;
+};
+
+class amount_node_t : public parent_node_t
+{
+public:
+ amount_t * amount;
+
+ amount_node_t(document_t * _document,
+ amount_t * _amount,
+ parent_node_t * _parent = NULL)
+ : parent_node_t(_document, _parent), amount(_amount) {
+ TRACE_CTOR(amount_node_t, "document_t *, amount_t *, parent_node_t *");
+ set_name(document_t::AMOUNT);
+ }
+ virtual ~amount_node_t() {
+ TRACE_DTOR(amount_node_t);
+ }
+
+ virtual node_t * children() const;
+
+ virtual value_t to_value() const {
+ return *amount;
+ }
+};
+
+class transaction_node_t : public parent_node_t
+{
+ mutable terminal_node_t * payee_virtual_node;
+
+public:
+ transaction_t * transaction;
+
+ transaction_node_t(document_t * _document,
+ transaction_t * _transaction,
+ parent_node_t * _parent = NULL)
+ : parent_node_t(_document, _parent), payee_virtual_node(NULL),
+ transaction(_transaction) {
+ TRACE_CTOR(transaction_node_t, "document_t *, transaction_t *, parent_node_t *");
+ set_name(document_t::TRANSACTION);
+ }
+ virtual ~transaction_node_t() {
+ TRACE_DTOR(transaction_node_t);
+ if (payee_virtual_node)
+ delete payee_virtual_node;
+ }
+
+ virtual node_t * children() const;
+ virtual node_t * lookup_child(int _name_id) const;
+ virtual value_t to_value() const;
+};
+
+class entry_node_t : public parent_node_t
+{
+ entry_t * entry;
+
+public:
+ entry_node_t(document_t * _document, entry_t * _entry,
+ parent_node_t * _parent = NULL)
+ : parent_node_t(_document, _parent), entry(_entry) {
+ TRACE_CTOR(entry_node_t, "document_t *, entry_t *, parent_node_t *");
+ set_name(document_t::ENTRY);
+ }
+ virtual ~entry_node_t() {
+ TRACE_DTOR(entry_node_t);
+ }
+
+ virtual node_t * children() const;
+ virtual node_t * lookup_child(int _name_id) const;
+
+ friend class transaction_node_t;
+};
+
+class account_node_t : public parent_node_t
+{
+ account_t * account;
+
+public:
+ account_node_t(document_t * _document, account_t * _account,
+ parent_node_t * _parent = NULL)
+ : parent_node_t(_document, _parent), account(_account) {
+ TRACE_CTOR(account_node_t, "document_t *, account_t *, parent_node_t *");
+ set_name(document_t::ACCOUNT);
+ }
+ virtual ~account_node_t() {
+ TRACE_DTOR(account_node_t);
+ }
+
+ virtual node_t * children() const;
+};
+
+class journal_node_t : public parent_node_t
+{
+ journal_t * journal;
+
+public:
+ journal_node_t(document_t * _document, journal_t * _journal,
+ parent_node_t * _parent = NULL)
+ : parent_node_t(_document, _parent), journal(_journal) {
+ TRACE_CTOR(journal_node_t, "document_t *, journal_t *, parent_node_t *");
+ set_name(document_t::JOURNAL);
+ }
+ virtual ~journal_node_t() {
+ TRACE_DTOR(journal_node_t);
+ }
+
+ virtual node_t * children() const;
+
+ friend class transaction_node_t;
+};
+
+template <typename T>
+inline parent_node_t * wrap_node(document_t * doc, T * item,
+ void * parent_node = NULL) {
+ assert(0);
+ return NULL;
+}
+
+template <>
+inline parent_node_t * wrap_node(document_t * doc, transaction_t * xact,
+ void * parent_node) {
+ return new transaction_node_t(doc, xact, (parent_node_t *)parent_node);
+}
+
+template <>
+inline parent_node_t * wrap_node(document_t * doc, entry_t * entry,
+ void * parent_node) {
+ return new entry_node_t(doc, entry, (parent_node_t *)parent_node);
+}
+
+template <>
+inline parent_node_t * wrap_node(document_t * doc, account_t * account,
+ void * parent_node) {
+ return new account_node_t(doc, account, (parent_node_t *)parent_node);
+}
+
+template <>
+inline parent_node_t * wrap_node(document_t * doc, journal_t * journal,
+ void * parent_node) {
+ return new journal_node_t(doc, journal, (parent_node_t *)parent_node);
+}
+
+} // namespace xml
+} // namespace ledger
+
+#endif // _XML_H