Added initial support for using builders from the various parsers; at the moment is just uses the xml_writer_t builder to output the contents of the ledger journal as XML

This commit is contained in:
John Wiegley 2007-05-14 11:09:06 +00:00
parent 3cc14c70d4
commit 77db7eb92f
14 changed files with 216 additions and 148 deletions

View file

@ -41,24 +41,15 @@ libledger_la_SOURCES = \
src/amount.cc \ src/amount.cc \
src/balance.cc \ src/balance.cc \
src/value.cc \ src/value.cc \
\ src/xml.cc \
src/session.cc \ src/xpath.cc \
src/builder.cc \
src/journal.cc \ src/journal.cc \
src/binary.cc \
src/qif.cc \
src/textual.cc \ src/textual.cc \
src/quotes.cc \ src/transform.cc \
src/csv.cc \
src/derive.cc \
src/emacs.cc \
src/format.cc \
src/reconcile.cc \
src/register.cc \ src/register.cc \
src/report.cc \ src/report.cc \
src/transform.cc \ src/session.cc
src/xml.cc \
src/xmlparse.cc \
src/xpath.cc
#if HAVE_EXPAT #if HAVE_EXPAT
#libledger_la_CPPFLAGS += -DHAVE_EXPAT=1 #libledger_la_CPPFLAGS += -DHAVE_EXPAT=1

1
src/builder.cc Normal file
View file

@ -0,0 +1 @@

View file

@ -4,6 +4,7 @@
#include "xml.h" #include "xml.h"
namespace ledger { namespace ledger {
namespace xml {
/** /**
* @class builder_t * @class builder_t
@ -22,61 +23,43 @@ public:
typedef uint_least32_t file_pos_t; typedef uint_least32_t file_pos_t;
typedef uint_least32_t file_line_t; typedef uint_least32_t file_line_t;
path pathname;
file_pos_t offset; file_pos_t offset;
file_line_t linenum; file_line_t linenum;
position_t() : offset(0), linenum(0) {} position_t() : offset(0), linenum(0) {}
explicit position_t(path _pathname, explicit position_t(file_pos_t _offset,
file_pos_t _offset,
file_line_t _linenum) file_line_t _linenum)
: pathname(_pathname), : offset(_offset), linenum(_linenum) {}
offset(_offset), linenum(_linenum) {}
}; };
position_t current_position; position_t current_position;
virtual void start_position(const std::istream& in, virtual void set_start_position(std::istream& in) {}
const path& pathname) { virtual void set_position(const position_t& position) {}
set_position(position_t(pathname, in.tellg(), 1)); virtual position_t& position() { return current_position; }
}
virtual void set_position(const position_t& position) {
current_position = position;
}
virtual position_t& position() {
return current_position;
}
virtual void push_attr(const string& name, virtual void push_attr(const string& name,
const string& value) = 0; const string& value) = 0;
virtual void push_attr(const nameid_t name_id, virtual void push_attr(const node_t::nameid_t name_id,
const string& value) = 0; const string& value) = 0;
virtual void begin_node(const string& name) = 0; virtual void begin_node(const string& name) = 0;
virtual void begin_node(const nameid_t name_id) = 0; virtual void begin_node(const node_t::nameid_t name_id) = 0;
template <typename T>
virtual void begin_node(typename T::pointer data) = 0;
virtual void push_node(const string& name, virtual void push_node(const string& name,
const optional<position_t>& end_pos) = 0; const optional<position_t>& end_pos = none) = 0;
virtual void push_node(const nameid_t name_id, virtual void push_node(const node_t::nameid_t name_id,
const optional<position_t>& end_pos) = 0; const optional<position_t>& end_pos = none) = 0;
virtual node_t * current_node() = 0; virtual node_t * current_node() = 0;
template <typename T>
virtual T * current_node() = 0;
virtual void append_text(const string& text) = 0; virtual void append_text(const string& text) = 0;
virtual node_t * end_node(const string& name, virtual node_t * end_node(const string& name,
const optional<position_t>& end_pos) = 0; const optional<position_t>& end_pos = none) = 0;
virtual node_t * end_node(const nameid_t name_id, virtual node_t * end_node(const node_t::nameid_t name_id,
const optional<position_t>& end_pos) = 0; const optional<position_t>& end_pos = none) = 0;
}; };
/** /**
@ -110,6 +93,14 @@ class xml_builder_t : public builder_t
*/ */
class journal_builder_t : public xml_builder_t class journal_builder_t : public xml_builder_t
{ {
public:
virtual void set_start_position(std::istream& in) {
set_position(position_t(in.tellg(), 1));
}
virtual void set_position(const position_t& position) {
current_position = position;
}
}; };
/** /**
@ -124,8 +115,67 @@ class journal_builder_t : public xml_builder_t
*/ */
class xml_writer_t : public builder_t class xml_writer_t : public builder_t
{ {
typedef std::list<std::pair<string, string> > attrs_list;
attrs_list current_attrs;
std::ostream& outs;
public:
xml_writer_t(std::ostream& _outs) : outs(_outs) {
outs << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
begin_node("ledger");
}
~xml_writer_t() {
end_node("ledger");
}
virtual void push_attr(const string& name,
const string& value) {
current_attrs.push_back(attrs_list::value_type(name, value));
}
virtual void push_attr(const node_t::nameid_t name_id,
const string& value) {
push_attr("hello", value);
}
virtual void begin_node(const string& name) {
outs << '<' << name;
foreach (const attrs_list::value_type& attr, current_attrs)
outs << ' ' << attr.first << "=\"" << attr.second << "\"";
current_attrs.clear();
outs << '>';
}
virtual void begin_node(const node_t::nameid_t name_id) {
begin_node("hello");
}
virtual void push_node(const string& name,
const optional<position_t>& end_pos = none) {
begin_node(name);
end_node(name, end_pos);
}
virtual void push_node(const node_t::nameid_t name_id,
const optional<position_t>& end_pos = none) {
push_node("hello", end_pos);
}
virtual node_t * current_node() { return NULL; }
virtual void append_text(const string& text) {
outs << text;
}
virtual node_t * end_node(const string& name,
const optional<position_t>& end_pos = none) {
outs << "</" << name << '>';
}
virtual node_t * end_node(const node_t::nameid_t name_id,
const optional<position_t>& end_pos = none) {
end_node("hello", end_pos);
}
}; };
} // namespace xml
} // namespace ledger } // namespace ledger
#endif // _BUILDER_H #endif // _BUILDER_H

View file

@ -186,7 +186,7 @@ void commodity_t::parse_symbol(std::istream& in, string& symbol)
symbol = buf; symbol = buf;
} }
void commodity_t::parse_symbol(const char *& p, string& symbol) void commodity_t::parse_symbol(char *& p, string& symbol)
{ {
if (*p == '"') { if (*p == '"') {
char * q = std::strchr(p + 1, '"'); char * q = std::strchr(p + 1, '"');

View file

@ -190,7 +190,7 @@ public:
optional<amount_t> value(const optional<moment_t>& moment = none); optional<amount_t> value(const optional<moment_t>& moment = none);
static void parse_symbol(std::istream& in, string& symbol); static void parse_symbol(std::istream& in, string& symbol);
static void parse_symbol(const char *& p, string& symbol); static void parse_symbol(char *& p, string& symbol);
static string parse_symbol(std::istream& in) { static string parse_symbol(std::istream& in) {
string temp; string temp;
parse_symbol(in, temp); parse_symbol(in, temp);

View file

@ -31,11 +31,12 @@
#include "utils.h" #include "utils.h"
#include "option.h" #include "option.h"
#if defined(HAVE_EXPAT) || defined(HAVE_XMLPARSE) //#if defined(HAVE_EXPAT) || defined(HAVE_XMLPARSE)
#include "gnucash.h" //#include "gnucash.h"
#endif //#endif
#include "qif.h" //#include "qif.h"
#include "ofx.h" //#include "ofx.h"
#include "builder.h"
#include <ledger.h> #include <ledger.h>
@ -211,7 +212,14 @@ static int read_and_report(report_t * report, int argc, char * argv[],
INFO_START(journal, "Read journal file"); INFO_START(journal, "Read journal file");
journal_t * journal = session.read_data(report->account); journal_t * journal = session.read_data(report->account);
{
textual_parser_t text_parser;
ifstream input(session.data_file);
xml::xml_writer_t writer(std::cout);
text_parser.parse(input, session.data_file, writer);
}
INFO_FINISH(journal); INFO_FINISH(journal);
return 0;
TRACE_FINISH(entry_text, 1); TRACE_FINISH(entry_text, 1);
TRACE_FINISH(entry_date, 1); TRACE_FINISH(entry_date, 1);
@ -459,7 +467,6 @@ int main(int argc, char * argv[], char * envp[])
#if 0 #if 0
session->register_parser(new binary_parser_t); session->register_parser(new binary_parser_t);
#endif
#if defined(HAVE_EXPAT) || defined(HAVE_XMLPARSE) #if defined(HAVE_EXPAT) || defined(HAVE_XMLPARSE)
session->register_parser(new xml::xml_parser_t); session->register_parser(new xml::xml_parser_t);
session->register_parser(new gnucash_parser_t); session->register_parser(new gnucash_parser_t);
@ -469,6 +476,7 @@ int main(int argc, char * argv[], char * envp[])
#endif #endif
session->register_parser(new qif_parser_t); session->register_parser(new qif_parser_t);
session->register_parser(new textual_parser_t); session->register_parser(new textual_parser_t);
#endif
std::auto_ptr<ledger::report_t> report(new ledger::report_t(session.get())); std::auto_ptr<ledger::report_t> report(new ledger::report_t(session.get()));

View file

@ -33,6 +33,7 @@
#define _PARSER_H #define _PARSER_H
#include "utils.h" #include "utils.h"
#include "builder.h"
namespace ledger { namespace ledger {
@ -46,10 +47,9 @@ class parser_t
virtual bool test(std::istream& in) const = 0; virtual bool test(std::istream& in) const = 0;
virtual unsigned int parse(std::istream& in, virtual void parse(std::istream& in,
journal_t * journal, const path& pathname,
account_t * master = NULL, xml::builder_t& builder) = 0;
const optional<path>& original = none) = 0;
}; };
DECLARE_EXCEPTION(parse_error); DECLARE_EXCEPTION(parse_error);
@ -65,6 +65,27 @@ inline char * skip_ws(char * ptr) {
return ptr; return ptr;
} }
inline char * next_element(char * buf, bool variable = false) {
for (char * p = buf; *p; p++) {
if (! (*p == ' ' || *p == '\t'))
continue;
if (! variable) {
*p = '\0';
return skip_ws(p + 1);
}
else if (*p == '\t') {
*p = '\0';
return skip_ws(p + 1);
}
else if (*(p + 1) == ' ') {
*p = '\0';
return skip_ws(p + 2);
}
}
return NULL;
}
inline char peek_next_nonws(std::istream& in) { inline char peek_next_nonws(std::istream& in) {
char c = in.peek(); char c = in.peek();
while (! in.eof() && std::isspace(c)) { while (! in.eof() && std::isspace(c)) {

View file

@ -68,36 +68,34 @@ void release_session_context()
#endif #endif
} }
unsigned int session_t::read_journal(std::istream& in, void session_t::read_journal(std::istream& in,
journal_t * journal, const path& pathname,
account_t * master, xml::builder_t& builder)
const optional<path>& original)
{ {
#if 0
if (! master) if (! master)
master = journal->master; master = journal->master;
#endif
for (ptr_list<parser_t>::iterator i = parsers.begin(); for (ptr_list<parser_t>::iterator i = parsers.begin();
i != parsers.end(); i != parsers.end();
i++) i++)
if (i->test(in)) if (i->test(in))
return i->parse(in, journal, master, original); i->parse(in, pathname, builder);
return 0;
} }
unsigned int session_t::read_journal(const path& pathname, void session_t::read_journal(const path& pathname,
journal_t * journal, xml::builder_t& builder)
account_t * master,
const optional<path>& original)
{ {
#if 0
journal->sources.push_back(pathname); journal->sources.push_back(pathname);
#endif
if (! exists(pathname)) if (! exists(pathname))
throw_(std::logic_error, "Cannot read file" << pathname); throw_(std::logic_error, "Cannot read file" << pathname);
ifstream stream(pathname); ifstream stream(pathname);
return read_journal(stream, journal, master, read_journal(stream, pathname, builder);
original ? original : pathname);
} }
void session_t::read_init() void session_t::read_init()
@ -115,6 +113,9 @@ void session_t::read_init()
journal_t * session_t::read_data(const string& master_account) journal_t * session_t::read_data(const string& master_account)
{ {
#if 1
return NULL;
#else
if (data_file.empty()) if (data_file.empty())
throw_(parse_error, "No journal file was specified (please use -f)"); throw_(parse_error, "No journal file was specified (please use -f)");
@ -180,6 +181,7 @@ journal_t * session_t::read_data(const string& master_account)
TRACE_STOP(parser, 1); TRACE_STOP(parser, 1);
return journal; return journal;
#endif
} }
bool session_t::resolve(const string& name, value_t& result, bool session_t::resolve(const string& name, value_t& result,

View file

@ -148,15 +148,11 @@ class session_t : public xml::xpath_t::scope_t
checked_delete(journal); checked_delete(journal);
} }
unsigned int read_journal(std::istream& in, void read_journal(std::istream& in,
journal_t * journal, const path& pathname,
account_t * master = NULL, xml::builder_t& builder);
const optional<path>& original = none); void read_journal(const path& pathname,
xml::builder_t& builder);
unsigned int read_journal(const path& pathname,
journal_t * journal,
account_t * master = NULL,
const optional<path>& original = none);
void read_init(); void read_init();

View file

@ -138,6 +138,7 @@ extern "C" {
#include <boost/filesystem/fstream.hpp> #include <boost/filesystem/fstream.hpp>
#include <boost/filesystem/operations.hpp> #include <boost/filesystem/operations.hpp>
#include <boost/filesystem/path.hpp> #include <boost/filesystem/path.hpp>
#include <boost/foreach.hpp>
#include <boost/function.hpp> #include <boost/function.hpp>
#include <boost/lambda/bind.hpp> #include <boost/lambda/bind.hpp>
#include <boost/lambda/lambda.hpp> #include <boost/lambda/lambda.hpp>

View file

@ -37,32 +37,9 @@ namespace ledger {
typedef xml::builder_t::position_t position_t; typedef xml::builder_t::position_t position_t;
namespace { void parse_transaction(xml::builder_t& builder,
inline char * next_element(char * buf, bool variable = false) { char * line,
for (char * p = buf; *p; p++) { position_t& end_of_line)
if (! (*p == ' ' || *p == '\t'))
continue;
if (! variable) {
*p = '\0';
return skip_ws(p + 1);
}
else if (*p == '\t') {
*p = '\0';
return skip_ws(p + 1);
}
else if (*(p + 1) == ' ') {
*p = '\0';
return skip_ws(p + 2);
}
}
return NULL;
}
}
void parse_transaction(builder_t& builder,
char * line,
position_t& end_of_line,
{ {
// First cut up the input line into its various parts. // First cut up the input line into its various parts.
@ -99,8 +76,8 @@ void parse_transaction(builder_t& builder,
// Setup the details for this node // Setup the details for this node
if (statep) { if (state) {
switch (*statep) { switch (*state) {
case '*': case '*':
builder.push_attr(CLEARED_ATTR, "yes"); builder.push_attr(CLEARED_ATTR, "yes");
break; break;
@ -131,9 +108,11 @@ void parse_transaction(builder_t& builder,
// Parse the optional amount // Parse the optional amount
builder.begin_node(AMOUNT_EXPR_NODE); if (amount) {
builder.append_text(account_path); builder.begin_node(AMOUNT_EXPR_NODE);
builder.end_node(AMOUNT_EXPR_NODE); builder.append_text(amount);
builder.end_node(AMOUNT_EXPR_NODE);
}
// Parse the optional note // Parse the optional note
@ -146,7 +125,7 @@ void parse_transaction(builder_t& builder,
builder.end_node(TRANSACTION_NODE, end_of_line); builder.end_node(TRANSACTION_NODE, end_of_line);
} }
bool parse_transactions(std::istream& in, builder_t& builder) bool parse_transactions(std::istream& in, xml::builder_t& builder)
{ {
TRACE_START(entry_xacts, 1, "Time spent parsing transactions:"); TRACE_START(entry_xacts, 1, "Time spent parsing transactions:");
@ -168,6 +147,7 @@ bool parse_transactions(std::istream& in, builder_t& builder)
break; break;
parse_transaction(builder, line, end_of_line); parse_transaction(builder, line, end_of_line);
added = true;
} }
TRACE_STOP(entry_xacts, 1); TRACE_STOP(entry_xacts, 1);
@ -175,10 +155,10 @@ bool parse_transactions(std::istream& in, builder_t& builder)
return added; return added;
} }
void parse_entry(std::istream& in, void parse_entry(std::istream& in,
builder_t& builder, xml::builder_t& builder,
char * line, char * line,
position_t& end_of_line) position_t& end_of_line)
{ {
TRACE_START(entry_text, 1, "Time spent preparing entry text:"); TRACE_START(entry_text, 1, "Time spent preparing entry text:");
@ -293,12 +273,13 @@ bool textual_parser_t::test(std::istream& in) const
return true; return true;
} }
void textual_parser_t::parse(std::istream& in, void textual_parser_t::parse(std::istream& in,
builder_t& builder) const path& pathname,
xml::builder_t& builder)
{ {
TRACE_START(parsing_total, 1, "Total time spent parsing text:"); TRACE_START(parsing_total, 1, "Total time spent parsing text:");
INFO("Parsing file '" << builder.position().pathname.string() << "'"); INFO("Parsing file '" << pathname.string() << "'");
builder.begin_node(JOURNAL_NODE); builder.begin_node(JOURNAL_NODE);
@ -312,7 +293,7 @@ void textual_parser_t::parse(std::istream& in,
end_of_line.offset += std::strlen(line) + 1; end_of_line.offset += std::strlen(line) + 1;
end_of_line.linenum++; end_of_line.linenum++;
PUSH_CONTEXT(); //PUSH_CONTEXT();
switch (line[0]) { switch (line[0]) {
case '\0': case '\0':
@ -481,7 +462,7 @@ void textual_parser_t::parse(std::istream& in,
break; break;
} }
POP_CONTEXT(builder_context(builder)); //POP_CONTEXT(builder_context(builder));
} }
builder.end_node(JOURNAL_NODE); builder.end_node(JOURNAL_NODE);

View file

@ -41,35 +41,11 @@ class textual_parser_t : public parser_t
public: public:
virtual bool test(std::istream& in) const; virtual bool test(std::istream& in) const;
virtual unsigned int parse(std::istream& in, virtual void parse(std::istream& in,
journal_t * journal, const path& pathname,
account_t * master = NULL, xml::builder_t& builder);
const optional<path>& original = none);
}; };
#if 0
void write_textual_journal(journal_t& journal, string path,
item_handler<transaction_t>& formatter,
const string& write_hdr_format,
std::ostream& out);
#endif
#if 0
class include_context : public file_context {
public:
include_context(const string& file, unsigned long line,
const string& desc = "") throw()
: file_context(file, line, desc) {}
virtual ~include_context() throw() {}
virtual void describe(std::ostream& out) const throw() {
if (! desc.empty())
out << desc << ": ";
out << "\"" << file << "\", line " << line << ":" << std::endl;
}
};
#endif
} // namespace ledger } // namespace ledger
#endif // _TEXTUAL_H #endif // _TEXTUAL_H

View file

@ -511,6 +511,8 @@ inline void throw_unexpected_error(char, char) {
* General utility functions * General utility functions
*/ */
#define foreach BOOST_FOREACH
namespace ledger { namespace ledger {
path resolve_path(const path& pathname); path resolve_path(const path& pathname);

View file

@ -34,7 +34,7 @@
#include "journal.h" #include "journal.h"
#include "value.h" #include "value.h"
#include "parser.h" //#include "parser.h"
namespace ledger { namespace ledger {
@ -47,6 +47,43 @@ namespace xml {
#define XML_NODE_IS_PARENT 0x1 #define XML_NODE_IS_PARENT 0x1
#define ACCOUNT_ATTR "account"
#define ACCOUNT_PATH_NODE "account-path"
#define AMOUNT_EXPR_NODE "amount-expr"
#define ARG_ATTR "arg"
#define AUTO_ENTRY_NODE "auto-entry"
#define BALANCE_ATTR "balance"
#define CHECKIN_NODE "checkin"
#define CLEARED_ATTR "cleared"
#define CODE_ATTR "code"
#define COMMODITY_CONVERSION_NODE "commodity-conversion"
#define COMMODITY_NOMARKET_NODE "commodity-nomarket"
#define COMMODITY_TEMPLATE_NODE "commodity-template"
#define CURRENT_YEAR_NODE "current-year"
#define DATE_ATTR "date"
#define DATE_EFF_ATTR "effective"
#define DEFAULT_ACCOUNT_NODE "default-account"
#define DIRECTIVE_NODE "directive"
#define ENTRY_NODE "entry"
#define FROM_ATTR "from"
#define JOURNAL_NODE "journal"
#define NAME_ATTR "name"
#define NOTE_NODE "note"
#define PAYEE_NODE "payee"
#define PENDING_ATTR "pending"
#define PERIOD_ENTRY_NODE "period-entry"
#define PERIOD_NODE "period"
#define PRICE_ATTR "price"
#define PRICE_HISTORY_NODE "price-history"
#define RULE_NODE "rule"
#define SYMBOL_ATTR "symbol"
#define TEMPLATE_ATTR "template"
#define TIME_ATTR "time"
#define TO_ATTR "to"
#define TRANSACTION_NODE "transaction"
#define VIRTUAL_ATTR "virtual"
#define YEAR_ATTR "year"
DECLARE_EXCEPTION(conversion_error); DECLARE_EXCEPTION(conversion_error);
class parent_node_t; class parent_node_t;
@ -290,6 +327,7 @@ public:
#endif #endif
}; };
#if 0
#if defined(HAVE_EXPAT) || defined(HAVE_XMLPARSE) #if defined(HAVE_EXPAT) || defined(HAVE_XMLPARSE)
class xml_parser_t : public parser_t class xml_parser_t : public parser_t
@ -305,6 +343,7 @@ class xml_parser_t : public parser_t
DECLARE_EXCEPTION(parse_error); DECLARE_EXCEPTION(parse_error);
#endif
#endif #endif
class commodity_node_t : public parent_node_t class commodity_node_t : public parent_node_t