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/balance.cc \
src/value.cc \
\
src/session.cc \
src/xml.cc \
src/xpath.cc \
src/builder.cc \
src/journal.cc \
src/binary.cc \
src/qif.cc \
src/textual.cc \
src/quotes.cc \
src/csv.cc \
src/derive.cc \
src/emacs.cc \
src/format.cc \
src/reconcile.cc \
src/transform.cc \
src/register.cc \
src/report.cc \
src/transform.cc \
src/xml.cc \
src/xmlparse.cc \
src/xpath.cc
src/session.cc
#if HAVE_EXPAT
#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"
namespace ledger {
namespace xml {
/**
* @class builder_t
@ -22,61 +23,43 @@ public:
typedef uint_least32_t file_pos_t;
typedef uint_least32_t file_line_t;
path pathname;
file_pos_t offset;
file_line_t linenum;
position_t() : offset(0), linenum(0) {}
explicit position_t(path _pathname,
file_pos_t _offset,
explicit position_t(file_pos_t _offset,
file_line_t _linenum)
: pathname(_pathname),
offset(_offset), linenum(_linenum) {}
: offset(_offset), linenum(_linenum) {}
};
position_t current_position;
virtual void start_position(const std::istream& in,
const path& pathname) {
set_position(position_t(pathname, in.tellg(), 1));
}
virtual void set_position(const position_t& position) {
current_position = position;
}
virtual position_t& position() {
return current_position;
}
virtual void set_start_position(std::istream& in) {}
virtual void set_position(const position_t& position) {}
virtual position_t& position() { return current_position; }
virtual void push_attr(const string& name,
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;
virtual void begin_node(const string& name) = 0;
virtual void begin_node(const nameid_t name_id) = 0;
template <typename T>
virtual void begin_node(typename T::pointer data) = 0;
virtual void begin_node(const node_t::nameid_t name_id) = 0;
virtual void push_node(const string& name,
const optional<position_t>& end_pos) = 0;
virtual void push_node(const nameid_t name_id,
const optional<position_t>& end_pos) = 0;
const optional<position_t>& end_pos = none) = 0;
virtual void push_node(const node_t::nameid_t name_id,
const optional<position_t>& end_pos = none) = 0;
virtual node_t * current_node() = 0;
template <typename T>
virtual T * current_node() = 0;
virtual void append_text(const string& text) = 0;
virtual node_t * end_node(const string& name,
const optional<position_t>& end_pos) = 0;
virtual node_t * end_node(const nameid_t name_id,
const optional<position_t>& end_pos) = 0;
const optional<position_t>& end_pos = none) = 0;
virtual node_t * end_node(const node_t::nameid_t name_id,
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
{
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
{
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
#endif // _BUILDER_H

View file

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

View file

@ -190,7 +190,7 @@ public:
optional<amount_t> value(const optional<moment_t>& moment = none);
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) {
string temp;
parse_symbol(in, temp);

View file

@ -31,11 +31,12 @@
#include "utils.h"
#include "option.h"
#if defined(HAVE_EXPAT) || defined(HAVE_XMLPARSE)
#include "gnucash.h"
#endif
#include "qif.h"
#include "ofx.h"
//#if defined(HAVE_EXPAT) || defined(HAVE_XMLPARSE)
//#include "gnucash.h"
//#endif
//#include "qif.h"
//#include "ofx.h"
#include "builder.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");
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);
return 0;
TRACE_FINISH(entry_text, 1);
TRACE_FINISH(entry_date, 1);
@ -459,7 +467,6 @@ int main(int argc, char * argv[], char * envp[])
#if 0
session->register_parser(new binary_parser_t);
#endif
#if defined(HAVE_EXPAT) || defined(HAVE_XMLPARSE)
session->register_parser(new xml::xml_parser_t);
session->register_parser(new gnucash_parser_t);
@ -469,6 +476,7 @@ int main(int argc, char * argv[], char * envp[])
#endif
session->register_parser(new qif_parser_t);
session->register_parser(new textual_parser_t);
#endif
std::auto_ptr<ledger::report_t> report(new ledger::report_t(session.get()));

View file

@ -33,6 +33,7 @@
#define _PARSER_H
#include "utils.h"
#include "builder.h"
namespace ledger {
@ -46,10 +47,9 @@ class parser_t
virtual bool test(std::istream& in) const = 0;
virtual unsigned int parse(std::istream& in,
journal_t * journal,
account_t * master = NULL,
const optional<path>& original = none) = 0;
virtual void parse(std::istream& in,
const path& pathname,
xml::builder_t& builder) = 0;
};
DECLARE_EXCEPTION(parse_error);
@ -65,6 +65,27 @@ inline char * skip_ws(char * 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) {
char c = in.peek();
while (! in.eof() && std::isspace(c)) {

View file

@ -68,36 +68,34 @@ void release_session_context()
#endif
}
unsigned int session_t::read_journal(std::istream& in,
journal_t * journal,
account_t * master,
const optional<path>& original)
void session_t::read_journal(std::istream& in,
const path& pathname,
xml::builder_t& builder)
{
#if 0
if (! master)
master = journal->master;
#endif
for (ptr_list<parser_t>::iterator i = parsers.begin();
i != parsers.end();
i++)
if (i->test(in))
return i->parse(in, journal, master, original);
return 0;
i->parse(in, pathname, builder);
}
unsigned int session_t::read_journal(const path& pathname,
journal_t * journal,
account_t * master,
const optional<path>& original)
void session_t::read_journal(const path& pathname,
xml::builder_t& builder)
{
#if 0
journal->sources.push_back(pathname);
#endif
if (! exists(pathname))
throw_(std::logic_error, "Cannot read file" << pathname);
ifstream stream(pathname);
return read_journal(stream, journal, master,
original ? original : pathname);
read_journal(stream, pathname, builder);
}
void session_t::read_init()
@ -115,6 +113,9 @@ void session_t::read_init()
journal_t * session_t::read_data(const string& master_account)
{
#if 1
return NULL;
#else
if (data_file.empty())
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);
return journal;
#endif
}
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);
}
unsigned int read_journal(std::istream& in,
journal_t * journal,
account_t * master = NULL,
const optional<path>& original = none);
unsigned int read_journal(const path& pathname,
journal_t * journal,
account_t * master = NULL,
const optional<path>& original = none);
void read_journal(std::istream& in,
const path& pathname,
xml::builder_t& builder);
void read_journal(const path& pathname,
xml::builder_t& builder);
void read_init();

View file

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

View file

@ -37,32 +37,9 @@ namespace ledger {
typedef xml::builder_t::position_t position_t;
namespace {
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;
}
}
void parse_transaction(builder_t& builder,
char * line,
position_t& end_of_line,
void parse_transaction(xml::builder_t& builder,
char * line,
position_t& end_of_line)
{
// 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
if (statep) {
switch (*statep) {
if (state) {
switch (*state) {
case '*':
builder.push_attr(CLEARED_ATTR, "yes");
break;
@ -131,9 +108,11 @@ void parse_transaction(builder_t& builder,
// Parse the optional amount
builder.begin_node(AMOUNT_EXPR_NODE);
builder.append_text(account_path);
builder.end_node(AMOUNT_EXPR_NODE);
if (amount) {
builder.begin_node(AMOUNT_EXPR_NODE);
builder.append_text(amount);
builder.end_node(AMOUNT_EXPR_NODE);
}
// Parse the optional note
@ -146,7 +125,7 @@ void parse_transaction(builder_t& builder,
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:");
@ -168,6 +147,7 @@ bool parse_transactions(std::istream& in, builder_t& builder)
break;
parse_transaction(builder, line, end_of_line);
added = true;
}
TRACE_STOP(entry_xacts, 1);
@ -175,10 +155,10 @@ bool parse_transactions(std::istream& in, builder_t& builder)
return added;
}
void parse_entry(std::istream& in,
builder_t& builder,
char * line,
position_t& end_of_line)
void parse_entry(std::istream& in,
xml::builder_t& builder,
char * line,
position_t& end_of_line)
{
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;
}
void textual_parser_t::parse(std::istream& in,
builder_t& builder)
void textual_parser_t::parse(std::istream& in,
const path& pathname,
xml::builder_t& builder)
{
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);
@ -312,7 +293,7 @@ void textual_parser_t::parse(std::istream& in,
end_of_line.offset += std::strlen(line) + 1;
end_of_line.linenum++;
PUSH_CONTEXT();
//PUSH_CONTEXT();
switch (line[0]) {
case '\0':
@ -481,7 +462,7 @@ void textual_parser_t::parse(std::istream& in,
break;
}
POP_CONTEXT(builder_context(builder));
//POP_CONTEXT(builder_context(builder));
}
builder.end_node(JOURNAL_NODE);

View file

@ -41,35 +41,11 @@ class textual_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 optional<path>& original = none);
virtual void parse(std::istream& in,
const path& pathname,
xml::builder_t& builder);
};
#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
#endif // _TEXTUAL_H

View file

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

View file

@ -34,7 +34,7 @@
#include "journal.h"
#include "value.h"
#include "parser.h"
//#include "parser.h"
namespace ledger {
@ -47,6 +47,43 @@ namespace xml {
#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);
class parent_node_t;
@ -290,6 +327,7 @@ public:
#endif
};
#if 0
#if defined(HAVE_EXPAT) || defined(HAVE_XMLPARSE)
class xml_parser_t : public parser_t
@ -305,6 +343,7 @@ class xml_parser_t : public parser_t
DECLARE_EXCEPTION(parse_error);
#endif
#endif
class commodity_node_t : public parent_node_t