Changed xpath to use intrusive_ptr; got the xml command working

This commit is contained in:
John Wiegley 2007-05-14 11:09:54 +00:00
parent 65af168838
commit f83705b847
21 changed files with 920 additions and 1386 deletions

View file

@ -37,6 +37,7 @@ libledger_la_SOURCES = \
src/utils.cc \ src/utils.cc \
src/times.cc \ src/times.cc \
src/mask.cc \ src/mask.cc \
src/abbrev.cc \
src/commodity.cc \ src/commodity.cc \
src/amount.cc \ src/amount.cc \
src/balance.cc \ src/balance.cc \
@ -49,7 +50,6 @@ libledger_la_SOURCES = \
src/textual.cc \ src/textual.cc \
src/binary.cc \ src/binary.cc \
src/transform.cc \ src/transform.cc \
src/register.cc \
src/report.cc \ src/report.cc \
src/session.cc src/session.cc
@ -94,6 +94,7 @@ libpyledger_la_SOURCES = \
pkginclude_HEADERS = \ pkginclude_HEADERS = \
src/abbrev.h \
src/amount.h \ src/amount.h \
src/balance.h \ src/balance.h \
src/balpair.h \ src/balpair.h \
@ -113,7 +114,6 @@ pkginclude_HEADERS = \
src/pyinterp.h \ src/pyinterp.h \
src/pyledger.h \ src/pyledger.h \
src/pyutils.h \ src/pyutils.h \
src/register.h \
src/report.h \ src/report.h \
src/scoped_execute.h \ src/scoped_execute.h \
src/session.h \ src/session.h \

View file

@ -293,7 +293,7 @@ bool entry_base_t::finalize()
entry_t::entry_t(const entry_t& e) entry_t::entry_t(const entry_t& e)
: entry_base_t(e), _date(e._date), _date_eff(e._date_eff), : entry_base_t(e), _date(e._date), _date_eff(e._date_eff),
code(e.code), payee(e.payee), data(NULL) code(e.code), payee(e.payee)
{ {
TRACE_CTOR(entry_t, "copy"); TRACE_CTOR(entry_t, "copy");
for (transactions_list::const_iterator i = transactions.begin(); for (transactions_list::const_iterator i = transactions.begin();
@ -538,9 +538,6 @@ journal_t::~journal_t()
assert(master); assert(master);
checked_delete(master); checked_delete(master);
if (document)
checked_delete(document);
// Don't bother unhooking each entry's transactions from the // Don't bother unhooking each entry's transactions from the
// accounts they refer to, because all accounts are about to // accounts they refer to, because all accounts are about to
// be deleted. // be deleted.

View file

@ -33,19 +33,10 @@
#define _JOURNAL_H #define _JOURNAL_H
#include "amount.h" #include "amount.h"
#include "xpath.h"
namespace ledger { namespace ledger {
namespace xml {
class document_t;
class xpath_t;
class transaction_node_t;
class entry_node_t;
class account_node_t;
class journal_node_t;
}
// These flags persist with the object // These flags persist with the object
#define TRANSACTION_NORMAL 0x0000 #define TRANSACTION_NORMAL 0x0000
#define TRANSACTION_VIRTUAL 0x0001 #define TRANSACTION_VIRTUAL 0x0001
@ -72,43 +63,20 @@ class transaction_t : public supports_flags<>
optional<amount_t> cost; optional<amount_t> cost;
optional<string> cost_expr; optional<string> cost_expr;
optional<string> note; optional<string> note;
unsigned long beg_pos;
unsigned long beg_line;
unsigned long end_pos;
unsigned long end_line;
typedef xml::transaction_node_t node_type;
mutable node_type * data;
static bool use_effective_date; static bool use_effective_date;
explicit transaction_t(account_t * _account = NULL) explicit transaction_t(account_t * _account = NULL)
: supports_flags<>(TRANSACTION_NORMAL), : supports_flags<>(TRANSACTION_NORMAL), entry(NULL),
entry(NULL), state(UNCLEARED), account(_account) {
state(UNCLEARED),
account(_account),
beg_pos(0),
beg_line(0),
end_pos(0),
end_line(0),
data(NULL) {
TRACE_CTOR(transaction_t, "account_t *"); TRACE_CTOR(transaction_t, "account_t *");
} }
explicit transaction_t(account_t * _account, explicit transaction_t(account_t * _account,
const amount_t& _amount, const amount_t& _amount,
unsigned int _flags = TRANSACTION_NORMAL, unsigned int _flags = TRANSACTION_NORMAL,
const optional<string> _note = none) const optional<string> _note = none)
: supports_flags<>(_flags), : supports_flags<>(_flags), entry(NULL), state(UNCLEARED),
entry(NULL), account(_account), amount(_amount), note(_note) {
state(UNCLEARED),
account(_account),
amount(_amount),
note(_note),
beg_pos(0),
beg_line(0),
end_pos(0),
end_line(0),
data(NULL) {
TRACE_CTOR(transaction_t, TRACE_CTOR(transaction_t,
"account_t *, const amount_t&, unsigned int, const string&"); "account_t *, const amount_t&, unsigned int, const string&");
} }
@ -123,12 +91,7 @@ class transaction_t : public supports_flags<>
amount_expr(xact.amount_expr), amount_expr(xact.amount_expr),
cost(xact.cost), cost(xact.cost),
cost_expr(xact.cost_expr), cost_expr(xact.cost_expr),
note(xact.note), note(xact.note) {
beg_pos(xact.beg_pos),
beg_line(xact.beg_line),
end_pos(xact.end_pos),
end_line(xact.end_line),
data(xact.data) {
TRACE_CTOR(transaction_t, "copy"); TRACE_CTOR(transaction_t, "copy");
} }
~transaction_t(); ~transaction_t();
@ -164,19 +127,12 @@ class entry_base_t
{ {
public: public:
journal_t * journal; journal_t * journal;
unsigned long src_idx;
unsigned long beg_pos;
unsigned long beg_line;
unsigned long end_pos;
unsigned long end_line;
transactions_list transactions; transactions_list transactions;
entry_base_t() : journal(NULL), entry_base_t() : journal(NULL) {
beg_pos(0), beg_line(0), end_pos(0), end_line(0) {
TRACE_CTOR(entry_base_t, ""); TRACE_CTOR(entry_base_t, "");
} }
entry_base_t(const entry_base_t& e) : journal(NULL), entry_base_t(const entry_base_t& e) : journal(NULL)
beg_pos(0), beg_line(0), end_pos(0), end_line(0)
{ {
TRACE_CTOR(entry_base_t, "copy"); TRACE_CTOR(entry_base_t, "copy");
for (transactions_list::const_iterator i = e.transactions.begin(); for (transactions_list::const_iterator i = e.transactions.begin();
@ -217,10 +173,7 @@ public:
optional<string> code; optional<string> code;
string payee; string payee;
typedef xml::entry_node_t node_type; entry_t() {
mutable node_type * data;
entry_t() : data(NULL) {
TRACE_CTOR(entry_t, ""); TRACE_CTOR(entry_t, "");
} }
entry_t(const entry_t& e); entry_t(const entry_t& e);
@ -337,9 +290,6 @@ class account_t
unsigned short depth; unsigned short depth;
accounts_map accounts; accounts_map accounts;
typedef xml::account_node_t node_type;
mutable node_type * data;
mutable ident_t ident; mutable ident_t ident;
mutable string _fullname; mutable string _fullname;
@ -347,7 +297,7 @@ class account_t
const string& _name = "", const string& _name = "",
const optional<string> _note = none) const optional<string> _note = none)
: parent(_parent), name(_name), note(_note), : parent(_parent), name(_name), note(_note),
depth(parent ? parent->depth + 1 : 0), data(NULL), ident(0) { depth(parent ? parent->depth + 1 : 0), ident(0) {
TRACE_CTOR(account_t, "account_t *, const string&, const string&"); TRACE_CTOR(account_t, "account_t *, const string&, const string&");
} }
~account_t(); ~account_t();
@ -432,16 +382,6 @@ class journal_t
char * item_pool; char * item_pool;
char * item_pool_end; char * item_pool_end;
// This is used for dynamically representing the journal data as an
// XML tree, to facilitate transformations without modifying any of
// the underlying structures (the transformers modify the XML tree
// -- perhaps even adding, changing or deleting nodes -- but they do
// not affect the basic data parsed from the journal file).
mutable xml::document_t * document;
typedef xml::journal_node_t node_type;
mutable node_type * data;
auto_entries_list auto_entries; auto_entries_list auto_entries;
period_entries_list period_entries; period_entries_list period_entries;
mutable accounts_map accounts_cache; mutable accounts_map accounts_cache;
@ -450,7 +390,7 @@ class journal_t
journal_t(session_t * _session) journal_t(session_t * _session)
: session(_session), basket(NULL), : session(_session), basket(NULL),
item_pool(NULL), item_pool_end(NULL), document(NULL) { item_pool(NULL), item_pool_end(NULL) {
TRACE_CTOR(journal_t, ""); TRACE_CTOR(journal_t, "");
master = new account_t(NULL, ""); master = new account_t(NULL, "");
master->journal = this; master->journal = this;

View file

@ -46,24 +46,12 @@
#include <value.h> #include <value.h>
#include <xpath.h> #include <xpath.h>
#include <format.h> #include <format.h>
//#include <quotes.h>
#include <session.h> #include <session.h>
#include <journal.h> #include <journal.h>
#include <parser.h> #include <parser.h>
#include <textual.h> #include <textual.h>
#include <binary.h> #include <binary.h>
#include <report.h> #include <report.h>
#include <transform.h> #include <transform.h>
#include <register.h>
#if 0
#include <emacs.h>
#include <csv.h>
#include <derive.h>
#include <reconcile.h>
#endif
#endif // _LEDGER_H #endif // _LEDGER_H

View file

@ -116,18 +116,17 @@ static int read_and_report(report_t * report, int argc, char * argv[],
string verb = *arg++; string verb = *arg++;
std::auto_ptr<xml::xpath_t::functor_t> command; xml::xpath_t::function_t command;
#if 0
if (verb == "register" || verb == "reg" || verb == "r") { if (verb == "register" || verb == "reg" || verb == "r") {
#if 1 command = register_command();
command.reset(new register_command); #if 0
#else
command = new format_command command = new format_command
("register", either_or(report->format_string, ("register", either_or(report->format_string,
report->session->register_format)); report->session->register_format));
#endif #endif
} }
#if 0
else if (verb == "balance" || verb == "bal" || verb == "b") { else if (verb == "balance" || verb == "bal" || verb == "b") {
if (! report->raw_mode) { if (! report->raw_mode) {
report->transforms.push_back(new accounts_transform); report->transforms.push_back(new accounts_transform);
@ -166,9 +165,10 @@ static int read_and_report(report_t * report, int argc, char * argv[],
command = new csv_command; command = new csv_command;
else if (verb == "emacs" || verb == "lisp") else if (verb == "emacs" || verb == "lisp")
command = new emacs_command; command = new emacs_command;
else
#endif #endif
else if (verb == "xml") if (verb == "xml")
command.reset(new xml_command); command = xml_command();
else if (verb == "expr") else if (verb == "expr")
; ;
else if (verb == "xpath") else if (verb == "xpath")
@ -198,10 +198,10 @@ static int read_and_report(report_t * report, int argc, char * argv[],
// jww (2007-04-19): This is an error, since command is an // jww (2007-04-19): This is an error, since command is an
// auto_ptr! // auto_ptr!
if (xml::xpath_t::op_t * def = report->lookup(buf)) if (xml::xpath_t::ptr_op_t def = report->lookup(buf))
command.reset(def->functor_obj()); command = def->as_function();
if (! command.get()) if (! command)
throw_(std::logic_error, string("Unrecognized command '") + verb + "'"); throw_(std::logic_error, string("Unrecognized command '") + verb + "'");
} }
@ -211,23 +211,15 @@ static int read_and_report(report_t * report, int argc, char * argv[],
session.read_init(); session.read_init();
INFO_START(journal, "Read journal file"); INFO_START(journal, "Read journal file");
journal_t * journal = session.read_data(report->account);
{
textual_parser_t text_parser;
ifstream input(session.data_file);
#if 1 xml::document_t xml_document(xml::LEDGER_NODE);
xml::document_t temp(xml::LEDGER_NODE); xml::document_builder_t builder(xml_document);
xml::document_builder_t builder(temp); journal_t * journal = session.create_journal();
text_parser.parse(input, session.data_file, builder); if (! session.read_data(builder, journal, report->account))
temp.print(std::cout); throw_(parse_error, "Failed to locate any journal entries; "
#else "did you specify a valid file with -f?");
xml::xml_writer_t writer(std::cout);
text_parser.parse(input, session.data_file, writer);
#endif
}
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);
@ -300,8 +292,7 @@ static int read_and_report(report_t * report, int argc, char * argv[],
*out << "Result of calculation: "; *out << "Result of calculation: ";
} }
xml::document_t temp(xml::LEDGER_NODE); *out << expr.calc(xml_document, report).strip_annotations() << std::endl;
*out << expr.calc(temp, report).strip_annotations() << std::endl;
return 0; return 0;
} }
@ -322,13 +313,14 @@ static int read_and_report(report_t * report, int argc, char * argv[],
// Create the an argument scope containing the report command's // Create the an argument scope containing the report command's
// arguments, and then invoke the command. // arguments, and then invoke the command.
std::auto_ptr<xml::xpath_t::scope_t> locals scoped_ptr<xml::xpath_t::scope_t> locals
(new xml::xpath_t::scope_t(report, xml::xpath_t::scope_t::ARGUMENT)); (new xml::xpath_t::scope_t(report, xml::xpath_t::scope_t::ARGUMENT));
locals->args = value_t::sequence_t(); locals->args = value_t::sequence_t();
locals->args.push_back(out); locals->args.push_back(out);
locals->args.push_back(journal->document); locals->args.push_back(&xml_document);
#if 0
if (command->wants_args) { if (command->wants_args) {
for (strings_list::iterator i = args.begin(); for (strings_list::iterator i = args.begin();
i != args.end(); i != args.end();
@ -381,14 +373,15 @@ static int read_and_report(report_t * report, int argc, char * argv[],
(string("//xact[account =~ /(") + regexps[0] + ")/]")); (string("//xact[account =~ /(") + regexps[0] + ")/]"));
#endif #endif
} }
#endif
INFO_START(transforms, "Applied transforms"); INFO_START(transforms, "Applied transforms");
report->apply_transforms(journal->document); report->apply_transforms(xml_document);
INFO_FINISH(transforms); INFO_FINISH(transforms);
INFO_START(command, "Did user command '" << verb << "'"); INFO_START(command, "Did user command '" << verb << "'");
value_t temp; value_t temp;
(*command)(temp, locals.get()); command(temp, locals.get());
INFO_FINISH(command); INFO_FINISH(command);
// Write out the binary cache, if need be // Write out the binary cache, if need be
@ -483,8 +476,8 @@ int main(int argc, char * argv[], char * envp[])
session->register_parser(new ofx_parser_t); session->register_parser(new ofx_parser_t);
#endif #endif
session->register_parser(new qif_parser_t); session->register_parser(new qif_parser_t);
session->register_parser(new textual_parser_t);
#endif #endif
session->register_parser(new textual_parser_t);
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

@ -32,17 +32,10 @@
#ifndef _NODE_H #ifndef _NODE_H
#define _NODE_H #define _NODE_H
#include "journal.h"
#include "value.h" #include "value.h"
//#include "parser.h" //#include "parser.h"
namespace ledger { namespace ledger {
class transaction_t;
class entry_t;
class account_t;
class journal_t;
namespace xml { namespace xml {
#define XML_NODE_IS_PARENT 0x1 #define XML_NODE_IS_PARENT 0x1

View file

@ -40,8 +40,8 @@ static ledger::option_t * find_option(const string& name);
namespace ledger { namespace ledger {
namespace { namespace {
xml::xpath_t::op_t * find_option(xml::xpath_t::scope_t * scope, xml::xpath_t::ptr_op_t find_option(xml::xpath_t::scope_t * scope,
const string& name) const string& name)
{ {
char buf[128]; char buf[128];
std::strcpy(buf, "option_"); std::strcpy(buf, "option_");
@ -57,7 +57,7 @@ namespace {
return scope->lookup(buf); return scope->lookup(buf);
} }
xml::xpath_t::op_t * find_option(xml::xpath_t::scope_t * scope, xml::xpath_t::ptr_op_t find_option(xml::xpath_t::scope_t * scope,
const char letter) const char letter)
{ {
char buf[9]; char buf[9];
@ -68,20 +68,20 @@ namespace {
return scope->lookup(buf); return scope->lookup(buf);
} }
void process_option(xml::xpath_t::functor_t * opt, xml::xpath_t::scope_t * scope, void process_option(const xml::xpath_t::function_t& opt,
const char * arg) xml::xpath_t::scope_t * scope, const char * arg)
{ {
#if 0 #if 0
try { try {
#endif #endif
std::auto_ptr<xml::xpath_t::scope_t> args; scoped_ptr<xml::xpath_t::scope_t> args;
if (arg) { if (arg) {
args.reset(new xml::xpath_t::scope_t(scope, xml::xpath_t::scope_t::ARGUMENT)); args.reset(new xml::xpath_t::scope_t(scope, xml::xpath_t::scope_t::ARGUMENT));
args->args.set_string(arg); args->args.set_string(arg);
} }
value_t temp; value_t temp;
(*opt)(temp, args.get()); opt(temp, args.get());
#if 0 #if 0
} }
catch (error * err) { catch (error * err) {
@ -99,13 +99,10 @@ namespace {
bool process_option(const string& name, xml::xpath_t::scope_t * scope, bool process_option(const string& name, xml::xpath_t::scope_t * scope,
const char * arg) const char * arg)
{ {
std::auto_ptr<xml::xpath_t::op_t> opt(find_option(scope, name)); xml::xpath_t::ptr_op_t opt(find_option(scope, name));
if (opt.get()) { if (opt) {
xml::xpath_t::functor_t * def = opt->functor_obj(); process_option(opt->as_function(), scope, arg);
if (def) { return true;
process_option(def, scope, arg);
return true;
}
} }
return false; return false;
} }
@ -134,7 +131,7 @@ void process_environment(const char ** envp, const string& tag,
#if 0 #if 0
try { try {
#endif #endif
if (! process_option(buf, scope, q + 1)) if (! process_option(string(buf), scope, q + 1))
#if 0 #if 0
throw new option_error("unknown option") throw new option_error("unknown option")
#endif #endif
@ -181,50 +178,37 @@ void process_arguments(int argc, char ** argv, const bool anywhere,
value = p; value = p;
} }
std::auto_ptr<xml::xpath_t::op_t> opt(find_option(scope, name)); xml::xpath_t::ptr_op_t opt(find_option(scope, name));
if (! opt.get()) if (! opt)
throw_(option_error, "illegal option --" << name); throw_(option_error, "illegal option --" << name);
xml::xpath_t::functor_t * def = opt->functor_obj(); if (/*def->wants_args &&*/ value == NULL) {
if (! def)
throw_(option_error, "illegal option --" << name);
if (def->wants_args && value == NULL) {
value = *++i; value = *++i;
if (value == NULL) if (value == NULL)
throw_(option_error, "missing option argument for --" << name); throw_(option_error, "missing option argument for --" << name);
} }
process_option(def, scope, value); process_option(opt->as_function(), scope, value);
} }
else if ((*i)[1] == '\0') { else if ((*i)[1] == '\0') {
throw_(option_error, "illegal option -"); throw_(option_error, "illegal option -");
} }
else { else {
std::list<xml::xpath_t::op_t *> option_queue; std::list<xml::xpath_t::ptr_op_t> option_queue;
int x = 1; int x = 1;
for (char c = (*i)[x]; c != '\0'; x++, c = (*i)[x]) { for (char c = (*i)[x]; c != '\0'; x++, c = (*i)[x]) {
xml::xpath_t::op_t * opt = find_option(scope, c); xml::xpath_t::ptr_op_t opt = find_option(scope, c);
if (! opt) if (! opt)
throw_(option_error, "illegal option -" << c); throw_(option_error, "illegal option -" << c);
xml::xpath_t::functor_t * def = opt->functor_obj();
if (! def)
throw_(option_error, "illegal option -" << c);
option_queue.push_back(opt); option_queue.push_back(opt);
} }
for (std::list<xml::xpath_t::op_t *>::iterator foreach (xml::xpath_t::ptr_op_t& o, option_queue) {
o = option_queue.begin();
o != option_queue.end();
o++) {
char * value = NULL; char * value = NULL;
#if 0
xml::xpath_t::functor_t * def = (*o)->functor_obj();
assert(def);
if (def->wants_args) { if (def->wants_args) {
#endif
value = *++i; value = *++i;
if (value == NULL) if (value == NULL)
throw_(option_error, "missing option argument for -" << throw_(option_error, "missing option argument for -" <<
@ -234,10 +218,11 @@ void process_arguments(int argc, char ** argv, const bool anywhere,
'?' '?'
#endif #endif
); );
#if 0
} }
process_option(def, scope, value); #endif
process_option(o->as_function(), scope, value);
checked_delete(*o);
} }
} }
} }

View file

@ -47,9 +47,9 @@ class parser_t
virtual bool test(std::istream& in) const = 0; virtual bool test(std::istream& in) const = 0;
virtual void parse(std::istream& in, virtual std::size_t parse(std::istream& in,
const path& pathname, const path& pathname,
xml::builder_t& builder) = 0; xml::builder_t& builder) = 0;
}; };
DECLARE_EXCEPTION(parse_error); DECLARE_EXCEPTION(parse_error);

View file

@ -198,7 +198,7 @@ void python_interpreter_t::functor_t::operator()(value_t& result,
else if (PyObject * err = PyErr_Occurred()) { else if (PyObject * err = PyErr_Occurred()) {
PyErr_Print(); PyErr_Print();
throw_(xml::xpath_t::calc_error, throw_(xml::xpath_t::calc_error,
"While calling Python function '" << name() << "'"); "While calling Python function '" /*<< name() <<*/ "'");
} else { } else {
assert(false); assert(false);
} }
@ -210,7 +210,7 @@ void python_interpreter_t::functor_t::operator()(value_t& result,
catch (const error_already_set&) { catch (const error_already_set&) {
PyErr_Print(); PyErr_Print();
throw_(xml::xpath_t::calc_error, throw_(xml::xpath_t::calc_error,
"While calling Python function '" << name() << "'"); "While calling Python function '" /*<< name() <<*/ "'");
} }
} }

View file

@ -70,26 +70,24 @@ class python_interpreter_t : public xml::xpath_t::scope_t
return eval(str, mode); return eval(str, mode);
} }
class functor_t : public xml::xpath_t::functor_t { class functor_t {
protected: protected:
boost::python::object func; boost::python::object func;
public: public:
functor_t(const string& name, boost::python::object _func) functor_t(const string& name, boost::python::object _func) : func(_func) {}
: xml::xpath_t::functor_t(name), func(_func) {}
virtual void operator()(value_t& result, xml::xpath_t::scope_t * locals); virtual void operator()(value_t& result, xml::xpath_t::scope_t * locals);
}; };
virtual void define(const string& name, xml::xpath_t::op_t * def) { virtual void define(const string& name, xml::xpath_t::ptr_op_t def) {
// Pass any definitions up to our parent // Pass any definitions up to our parent
parent->define(name, def); parent->define(name, def);
} }
virtual xml::xpath_t::op_t * lookup(const string& name) { virtual xml::xpath_t::ptr_op_t lookup(const string& name) {
boost::python::object func = eval(name); if (boost::python::object func = eval(name))
if (! func) return xml::xpath_t::wrap_functor(functor_t(name, func));
else
return parent ? parent->lookup(name) : NULL; return parent ? parent->lookup(name) : NULL;
return xml::xpath_t::wrap_functor(new functor_t(name, func));
} }
class lambda_t : public functor_t { class lambda_t : public functor_t {

View file

@ -38,12 +38,10 @@ report_t::~report_t()
TRACE_DTOR(report_t); TRACE_DTOR(report_t);
} }
void report_t::apply_transforms(xml::document_t * document) void report_t::apply_transforms(xml::document_t& document)
{ {
for (ptr_list<transform_t>::iterator i = transforms.begin(); foreach (transform_t& transform, transforms)
i != transforms.end(); transform.execute(document);
i++)
i->execute(document);
} }
void report_t::abbrev(value_t& result, xml::xpath_t::scope_t * locals) void report_t::abbrev(value_t& result, xml::xpath_t::scope_t * locals)
@ -107,7 +105,7 @@ bool report_t::resolve(const string& name, value_t& result,
return xml::xpath_t::scope_t::resolve(name, result, locals); return xml::xpath_t::scope_t::resolve(name, result, locals);
} }
xml::xpath_t::op_t * report_t::lookup(const string& name) xml::xpath_t::ptr_op_t report_t::lookup(const string& name)
{ {
const char * p = name.c_str(); const char * p = name.c_str();
switch (*p) { switch (*p) {
@ -122,88 +120,91 @@ xml::xpath_t::op_t * report_t::lookup(const string& name)
else else
#endif #endif
if (std::strcmp(p, "amount") == 0) if (std::strcmp(p, "amount") == 0)
return MAKE_FUNCTOR(report_t, option_amount); return MAKE_FUNCTOR(report_t::option_amount);
break; break;
case 'b': case 'b':
if (std::strcmp(p, "bar") == 0) if (std::strcmp(p, "bar") == 0)
return MAKE_FUNCTOR(report_t, option_bar); return MAKE_FUNCTOR(report_t::option_bar);
break; break;
#if 0 #if 0
case 'c': case 'c':
if (std::strcmp(p, "clean") == 0) if (std::strcmp(p, "clean") == 0)
return MAKE_FUNCTOR(report_t, option_clean); return MAKE_FUNCTOR(report_t::option_clean);
else if (std::strcmp(p, "compact") == 0) else if (std::strcmp(p, "compact") == 0)
return MAKE_FUNCTOR(report_t, option_compact); return MAKE_FUNCTOR(report_t::option_compact);
break; break;
#endif #endif
case 'e': case 'e':
#if 0 #if 0
if (std::strcmp(p, "entries") == 0) if (std::strcmp(p, "entries") == 0)
return MAKE_FUNCTOR(report_t, option_entries); return MAKE_FUNCTOR(report_t::option_entries);
else if (std::strcmp(p, "eval") == 0) else if (std::strcmp(p, "eval") == 0)
return MAKE_FUNCTOR(report_t, option_eval); return MAKE_FUNCTOR(report_t::option_eval);
else if (std::strcmp(p, "exclude") == 0) else if (std::strcmp(p, "exclude") == 0)
return MAKE_FUNCTOR(report_t, option_remove); return MAKE_FUNCTOR(report_t::option_remove);
#endif #endif
break; break;
case 'f': case 'f':
#if 0
if (std::strcmp(p, "foo") == 0) if (std::strcmp(p, "foo") == 0)
return MAKE_FUNCTOR(report_t, option_foo); return MAKE_FUNCTOR(report_t::option_foo);
else if (std::strcmp(p, "format") == 0) else
return MAKE_FUNCTOR(report_t, option_format); #endif
if (std::strcmp(p, "format") == 0)
return MAKE_FUNCTOR(report_t::option_format);
break; break;
case 'i': case 'i':
#if 0 #if 0
if (std::strcmp(p, "include") == 0) if (std::strcmp(p, "include") == 0)
return MAKE_FUNCTOR(report_t, option_select); return MAKE_FUNCTOR(report_t::option_select);
#endif #endif
break; break;
case 'l': case 'l':
#if 0 #if 0
if (! *(p + 1) || std::strcmp(p, "limit") == 0) if (! *(p + 1) || std::strcmp(p, "limit") == 0)
return MAKE_FUNCTOR(report_t, option_limit); return MAKE_FUNCTOR(report_t::option_limit);
#endif #endif
break; break;
#if 0 #if 0
case 'm': case 'm':
if (std::strcmp(p, "merge") == 0) if (std::strcmp(p, "merge") == 0)
return MAKE_FUNCTOR(report_t, option_merge); return MAKE_FUNCTOR(report_t::option_merge);
break; break;
#endif #endif
case 'r': case 'r':
#if 0 #if 0
if (std::strcmp(p, "remove") == 0) if (std::strcmp(p, "remove") == 0)
return MAKE_FUNCTOR(report_t, option_remove); return MAKE_FUNCTOR(report_t::option_remove);
#endif #endif
break; break;
#if 0 #if 0
case 's': case 's':
if (std::strcmp(p, "select") == 0) if (std::strcmp(p, "select") == 0)
return MAKE_FUNCTOR(report_t, option_select); return MAKE_FUNCTOR(report_t::option_select);
else if (std::strcmp(p, "split") == 0) else if (std::strcmp(p, "split") == 0)
return MAKE_FUNCTOR(report_t, option_split); return MAKE_FUNCTOR(report_t::option_split);
break; break;
#endif #endif
case 't': case 't':
if (! *(p + 1)) if (! *(p + 1))
return MAKE_FUNCTOR(report_t, option_amount); return MAKE_FUNCTOR(report_t::option_amount);
else if (std::strcmp(p, "total") == 0) else if (std::strcmp(p, "total") == 0)
return MAKE_FUNCTOR(report_t, option_total); return MAKE_FUNCTOR(report_t::option_total);
break; break;
case 'T': case 'T':
if (! *(p + 1)) if (! *(p + 1))
return MAKE_FUNCTOR(report_t, option_total); return MAKE_FUNCTOR(report_t::option_total);
break; break;
} }
} }

View file

@ -74,7 +74,7 @@ class report_t : public xml::xpath_t::scope_t
virtual ~report_t(); virtual ~report_t();
void apply_transforms(xml::document_t * document); void apply_transforms(xml::document_t& document);
// //
// Utility functions for value expressions // Utility functions for value expressions
@ -163,7 +163,7 @@ class report_t : public xml::xpath_t::scope_t
virtual bool resolve(const string& name, value_t& result, virtual bool resolve(const string& name, value_t& result,
xml::xpath_t::scope_t * locals); xml::xpath_t::scope_t * locals);
virtual xml::xpath_t::op_t * lookup(const string& name); virtual xml::xpath_t::ptr_op_t lookup(const string& name);
}; };
string abbrev(const string& str, unsigned int width, string abbrev(const string& str, unsigned int width,

View file

@ -68,24 +68,24 @@ void release_session_context()
#endif #endif
} }
void session_t::read_journal(std::istream& in, std::size_t session_t::read_journal(std::istream& in,
const path& pathname, const path& pathname,
xml::builder_t& builder) xml::builder_t& builder)
{ {
#if 0 #if 0
if (! master) if (! master)
master = journal->master; master = journal->master;
#endif #endif
for (ptr_list<parser_t>::iterator i = parsers.begin(); foreach (parser_t& parser, parsers)
i != parsers.end(); if (parser.test(in))
i++) return parser.parse(in, pathname, builder);
if (i->test(in))
i->parse(in, pathname, builder); return 0;
} }
void session_t::read_journal(const path& pathname, std::size_t session_t::read_journal(const path& pathname,
xml::builder_t& builder) xml::builder_t& builder)
{ {
#if 0 #if 0
journal->sources.push_back(pathname); journal->sources.push_back(pathname);
@ -95,7 +95,7 @@ void session_t::read_journal(const path& pathname,
throw_(std::logic_error, "Cannot read file" << pathname); throw_(std::logic_error, "Cannot read file" << pathname);
ifstream stream(pathname); ifstream stream(pathname);
read_journal(stream, pathname, builder); return read_journal(stream, pathname, builder);
} }
void session_t::read_init() void session_t::read_init()
@ -111,21 +111,16 @@ void session_t::read_init()
// jww (2006-09-15): Read initialization options here! // jww (2006-09-15): Read initialization options here!
} }
journal_t * session_t::read_data(const string& master_account) std::size_t session_t::read_data(xml::builder_t& builder,
journal_t * journal,
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)");
TRACE_START(parser, 1, "Parsing journal file"); TRACE_START(parser, 1, "Parsing journal file");
journal_t * journal = new_journal(); std::size_t entry_count = 0;
journal->document = new xml::document_t;
journal->document->set_top(xml::wrap_node(journal->document, journal));
unsigned int entry_count = 0;
DEBUG("ledger.cache", "3. use_cache = " << use_cache); DEBUG("ledger.cache", "3. use_cache = " << use_cache);
@ -136,8 +131,7 @@ journal_t * session_t::read_data(const string& master_account)
scoped_variable<optional<path> > scoped_variable<optional<path> >
save_price_db(journal->price_db, price_db); save_price_db(journal->price_db, price_db);
ifstream stream(*cache_file); entry_count += read_journal(*cache_file, builder);
entry_count += read_journal(stream, journal, NULL, data_file);
if (entry_count > 0) if (entry_count > 0)
cache_dirty = false; cache_dirty = false;
} }
@ -150,7 +144,7 @@ journal_t * session_t::read_data(const string& master_account)
journal->price_db = price_db; journal->price_db = price_db;
if (journal->price_db && exists(*journal->price_db)) { if (journal->price_db && exists(*journal->price_db)) {
if (read_journal(*journal->price_db, journal)) { if (read_journal(*journal->price_db, builder)) {
throw_(parse_error, "Entries not allowed in price history file"); throw_(parse_error, "Entries not allowed in price history file");
} else { } else {
DEBUG("ledger.cache", DEBUG("ledger.cache",
@ -163,10 +157,10 @@ journal_t * session_t::read_data(const string& master_account)
if (data_file == "-") { if (data_file == "-") {
use_cache = false; use_cache = false;
journal->sources.push_back("<stdin>"); journal->sources.push_back("<stdin>");
entry_count += read_journal(std::cin, journal, acct); entry_count += read_journal(std::cin, "<stdin>", builder);
} }
else if (exists(data_file)) { else if (exists(data_file)) {
entry_count += read_journal(data_file, journal, acct); entry_count += read_journal(data_file, builder);
if (journal->price_db) if (journal->price_db)
journal->sources.push_back(*journal->price_db); journal->sources.push_back(*journal->price_db);
} }
@ -174,14 +168,9 @@ journal_t * session_t::read_data(const string& master_account)
VERIFY(journal->valid()); VERIFY(journal->valid());
if (entry_count == 0)
throw_(parse_error, "Failed to locate any journal entries; "
"did you specify a valid file with -f?");
TRACE_STOP(parser, 1); TRACE_STOP(parser, 1);
return journal; return entry_count;
#endif
} }
bool session_t::resolve(const string& name, value_t& result, bool session_t::resolve(const string& name, value_t& result,
@ -221,7 +210,7 @@ bool session_t::resolve(const string& name, value_t& result,
return xml::xpath_t::scope_t::resolve(name, result, locals); return xml::xpath_t::scope_t::resolve(name, result, locals);
} }
xml::xpath_t::op_t * session_t::lookup(const string& name) xml::xpath_t::ptr_op_t session_t::lookup(const string& name)
{ {
const char * p = name.c_str(); const char * p = name.c_str();
switch (*p) { switch (*p) {
@ -231,24 +220,26 @@ xml::xpath_t::op_t * session_t::lookup(const string& name)
switch (*p) { switch (*p) {
case 'd': case 'd':
if (std::strcmp(p, "debug") == 0) if (std::strcmp(p, "debug") == 0)
return MAKE_FUNCTOR(session_t, option_debug); return MAKE_FUNCTOR(session_t::option_debug);
break; break;
case 'f': case 'f':
if (! *(p + 1) || std::strcmp(p, "file") == 0) if (! *(p + 1) || std::strcmp(p, "file") == 0)
return MAKE_FUNCTOR(session_t, option_file); return MAKE_FUNCTOR(session_t::option_file);
break; break;
case 't': case 't':
if (std::strcmp(p, "trace") == 0) if (std::strcmp(p, "trace") == 0)
return MAKE_FUNCTOR(session_t, option_trace); return MAKE_FUNCTOR(session_t::option_trace);
break; break;
case 'v': case 'v':
#if 0
if (! *(p + 1) || std::strcmp(p, "verbose") == 0) if (! *(p + 1) || std::strcmp(p, "verbose") == 0)
return MAKE_FUNCTOR(session_t, option_verbose); return MAKE_FUNCTOR(session_t::option_verbose);
else if (std::strcmp(p, "verify") == 0) else if (std::strcmp(p, "verify") == 0)
return MAKE_FUNCTOR(session_t, option_verify); return MAKE_FUNCTOR(session_t::option_verify);
#endif
break; break;
} }
} }

View file

@ -32,9 +32,10 @@
#ifndef _SESSION_H #ifndef _SESSION_H
#define _SESSION_H #define _SESSION_H
#include "xpath.h"
#include "journal.h" #include "journal.h"
#include "parser.h" #include "parser.h"
#include "register.h" #include "abbrev.h"
namespace ledger { namespace ledger {
@ -131,7 +132,7 @@ class session_t : public xml::xpath_t::scope_t
TRACE_DTOR(session_t); TRACE_DTOR(session_t);
} }
journal_t * new_journal() { journal_t * create_journal() {
journal_t * journal = new journal_t(this); journal_t * journal = new journal_t(this);
journals.push_back(journal); journals.push_back(journal);
return journal; return journal;
@ -148,15 +149,17 @@ class session_t : public xml::xpath_t::scope_t
checked_delete(journal); checked_delete(journal);
} }
void read_journal(std::istream& in, std::size_t read_journal(std::istream& in,
const path& pathname, const path& pathname,
xml::builder_t& builder); xml::builder_t& builder);
void read_journal(const path& pathname, std::size_t read_journal(const path& pathname,
xml::builder_t& builder); xml::builder_t& builder);
void read_init(); void read_init();
journal_t * read_data(const string& master_account = ""); std::size_t read_data(xml::builder_t& builder,
journal_t * journal,
const string& master_account = "");
void register_parser(parser_t * parser) { void register_parser(parser_t * parser) {
parsers.push_back(parser); parsers.push_back(parser);
@ -179,7 +182,7 @@ class session_t : public xml::xpath_t::scope_t
virtual bool resolve(const string& name, value_t& result, virtual bool resolve(const string& name, value_t& result,
xml::xpath_t::scope_t * locals = NULL); xml::xpath_t::scope_t * locals = NULL);
virtual xml::xpath_t::op_t * lookup(const string& name); virtual xml::xpath_t::ptr_op_t lookup(const string& name);
// //
// Debug options // Debug options

View file

@ -140,6 +140,7 @@ extern "C" {
#include <boost/filesystem/path.hpp> #include <boost/filesystem/path.hpp>
#include <boost/foreach.hpp> #include <boost/foreach.hpp>
#include <boost/function.hpp> #include <boost/function.hpp>
#include <boost/intrusive_ptr.hpp>
#include <boost/lambda/bind.hpp> #include <boost/lambda/bind.hpp>
#include <boost/lambda/lambda.hpp> #include <boost/lambda/lambda.hpp>
#include <boost/lexical_cast.hpp> #include <boost/lexical_cast.hpp>
@ -154,5 +155,6 @@ extern "C" {
#include <boost/ptr_container/ptr_list.hpp> #include <boost/ptr_container/ptr_list.hpp>
#include <boost/ptr_container/ptr_vector.hpp> #include <boost/ptr_container/ptr_vector.hpp>
#include <boost/regex.hpp> #include <boost/regex.hpp>
#include <boost/variant.hpp>
#endif // _SYSTEM_HH #endif // _SYSTEM_HH

View file

@ -275,9 +275,9 @@ bool textual_parser_t::test(std::istream& in) const
return true; return true;
} }
void textual_parser_t::parse(std::istream& in, std::size_t textual_parser_t::parse(std::istream& in,
const path& pathname, const path& pathname,
builder_t& builder) builder_t& builder)
{ {
TRACE_START(parsing_total, 1, "Total time spent parsing text:"); TRACE_START(parsing_total, 1, "Total time spent parsing text:");
@ -285,6 +285,8 @@ void textual_parser_t::parse(std::istream& in,
builder.begin_node(JOURNAL_NODE); builder.begin_node(JOURNAL_NODE);
std::size_t count = 0;
while (in.good() && ! in.eof()) { while (in.good() && ! in.eof()) {
static char line[MAX_LINE + 1]; static char line[MAX_LINE + 1];
in.getline(line, MAX_LINE); in.getline(line, MAX_LINE);
@ -460,6 +462,7 @@ void textual_parser_t::parse(std::istream& in,
default: default:
TRACE_START(entries, 1, "Time spent handling entries:"); TRACE_START(entries, 1, "Time spent handling entries:");
parse_entry(in, builder, line, end_of_line); parse_entry(in, builder, line, end_of_line);
count++;
TRACE_STOP(entries, 1); TRACE_STOP(entries, 1);
break; break;
} }
@ -470,6 +473,8 @@ void textual_parser_t::parse(std::istream& in,
builder.end_node(JOURNAL_NODE); builder.end_node(JOURNAL_NODE);
TRACE_STOP(parsing_total, 1); TRACE_STOP(parsing_total, 1);
return count;
} }
} // namespace ledger } // namespace ledger

View file

@ -41,9 +41,9 @@ class textual_parser_t : public parser_t
public: public:
virtual bool test(std::istream& in) const; virtual bool test(std::istream& in) const;
virtual void parse(std::istream& in, virtual std::size_t parse(std::istream& in,
const path& pathname, const path& pathname,
xml::builder_t& builder); xml::builder_t& builder);
}; };
} // namespace ledger } // namespace ledger

View file

@ -34,7 +34,7 @@
namespace ledger { namespace ledger {
#if 0 #if 0
void populate_account(account_t& acct, xml::document_t * document) void populate_account(account_t& acct, xml::document_t& document)
{ {
if (! acct.parent) if (! acct.parent)
return; return;
@ -61,7 +61,7 @@ void populate_account(account_t& acct, xml::document_t * document)
} }
class populate_accounts : public repitem_t::select_callback_t { class populate_accounts : public repitem_t::select_callback_t {
virtual void operator()(xml::document_t * document) { virtual void operator()(xml::document_t& document) {
if (item->kind == repitem_t::TRANSACTION) { if (item->kind == repitem_t::TRANSACTION) {
item->extract(); item->extract();
populate_account(*static_cast<xact_repitem_t *>(item)->account(), item); populate_account(*static_cast<xact_repitem_t *>(item)->account(), item);
@ -70,13 +70,13 @@ class populate_accounts : public repitem_t::select_callback_t {
}; };
class clear_account_data : public repitem_t::select_callback_t { class clear_account_data : public repitem_t::select_callback_t {
virtual void operator()(xml::document_t * document) { virtual void operator()(xml::document_t& document) {
if (item->kind == repitem_t::ACCOUNT) if (item->kind == repitem_t::ACCOUNT)
static_cast<account_repitem_t *>(item)->account->data = NULL; static_cast<account_repitem_t *>(item)->account->data = NULL;
} }
}; };
void accounts_transform::execute(xml::document_t * document) void accounts_transform::execute(xml::document_t& document)
{ {
populate_accounts cb1; populate_accounts cb1;
items->select_all(cb1); items->select_all(cb1);
@ -99,7 +99,7 @@ void accounts_transform::execute(xml::document_t * document)
items->select_all(cb2); items->select_all(cb2);
} }
void compact_transform::execute(xml::document_t * document) void compact_transform::execute(xml::document_t& document)
{ {
for (repitem_t * i = items; i; i = i->next) { for (repitem_t * i = items; i; i = i->next) {
if (i->kind == repitem_t::ACCOUNT) { if (i->kind == repitem_t::ACCOUNT) {
@ -138,7 +138,7 @@ void compact_transform::execute(xml::document_t * document)
} }
} }
void clean_transform::execute(xml::document_t * document) void clean_transform::execute(xml::document_t& document)
{ {
repitem_t * i = items; repitem_t * i = items;
while (i) { while (i) {
@ -169,11 +169,11 @@ void clean_transform::execute(xml::document_t * document)
} }
} }
void entries_transform::execute(xml::document_t * document) void entries_transform::execute(xml::document_t& document)
{ {
} }
void optimize_transform::execute(xml::document_t * document) void optimize_transform::execute(xml::document_t& document)
{ {
for (repitem_t * i = items; i; i = i->next) { for (repitem_t * i = items; i; i = i->next) {
if (i->kind == repitem_t::ENTRY) { if (i->kind == repitem_t::ENTRY) {
@ -194,7 +194,7 @@ void optimize_transform::execute(xml::document_t * document)
} }
} }
void split_transform::execute(xml::document_t * document) void split_transform::execute(xml::document_t& document)
{ {
for (repitem_t * i = items; i; i = i->next) { for (repitem_t * i = items; i; i = i->next) {
if (i->contents && i->contents->next) { if (i->contents && i->contents->next) {
@ -236,7 +236,7 @@ void split_transform::execute(xml::document_t * document)
} }
} }
void merge_transform::execute(xml::document_t * document) void merge_transform::execute(xml::document_t& document)
{ {
for (repitem_t * i = items; i; i = i->next) { for (repitem_t * i = items; i; i = i->next) {
if (i->next) { if (i->next) {
@ -290,13 +290,13 @@ namespace {
#define REPITEM_FLAGGED 0x1 #define REPITEM_FLAGGED 0x1
class mark_selected : public repitem_t::select_callback_t { class mark_selected : public repitem_t::select_callback_t {
virtual void operator()(xml::document_t * document) { virtual void operator()(xml::document_t& document) {
item->flags |= REPITEM_FLAGGED; item->flags |= REPITEM_FLAGGED;
} }
}; };
class mark_selected_and_ancestors : public repitem_t::select_callback_t { class mark_selected_and_ancestors : public repitem_t::select_callback_t {
virtual void operator()(xml::document_t * document) { virtual void operator()(xml::document_t& document) {
while (item->parent) { while (item->parent) {
item->flags |= REPITEM_FLAGGED; item->flags |= REPITEM_FLAGGED;
item = item->parent; item = item->parent;
@ -305,27 +305,27 @@ namespace {
}; };
class delete_unmarked : public repitem_t::select_callback_t { class delete_unmarked : public repitem_t::select_callback_t {
virtual void operator()(xml::document_t * document) { virtual void operator()(xml::document_t& document) {
if (item->parent && ! (item->flags & REPITEM_FLAGGED)) if (item->parent && ! (item->flags & REPITEM_FLAGGED))
checked_delete(item); checked_delete(item);
} }
}; };
class delete_marked : public repitem_t::select_callback_t { class delete_marked : public repitem_t::select_callback_t {
virtual void operator()(xml::document_t * document) { virtual void operator()(xml::document_t& document) {
if (item->flags & REPITEM_FLAGGED) if (item->flags & REPITEM_FLAGGED)
checked_delete(item); checked_delete(item);
} }
}; };
class clear_flags : public repitem_t::select_callback_t { class clear_flags : public repitem_t::select_callback_t {
virtual void operator()(xml::document_t * document) { virtual void operator()(xml::document_t& document) {
item->flags = 0; item->flags = 0;
} }
}; };
} }
void select_transform::execute(xml::document_t * document) void select_transform::execute(xml::document_t& document)
{ {
if (! path) { if (! path) {
items->clear(); items->clear();
@ -340,7 +340,7 @@ void select_transform::execute(xml::document_t * document)
items->select_all(cb3); items->select_all(cb3);
} }
void remove_transform::execute(xml::document_t * document) void remove_transform::execute(xml::document_t& document)
{ {
if (! path) if (! path)
return; return;

View file

@ -39,38 +39,38 @@ namespace ledger {
class transform_t { class transform_t {
public: public:
virtual ~transform_t() {} virtual ~transform_t() {}
virtual void execute(xml::document_t * document) = 0; virtual void execute(xml::document_t& document) = 0;
}; };
class check_transform : public transform_t { class check_transform : public transform_t {
// --check checks the validity of the item list. // --check checks the validity of the item list.
public: public:
virtual void execute(xml::document_t * document); virtual void execute(xml::document_t& document);
}; };
class accounts_transform : public transform_t { class accounts_transform : public transform_t {
// --accounts transforms the report tree into an account-wise view. // --accounts transforms the report tree into an account-wise view.
public: public:
virtual void execute(xml::document_t * document); virtual void execute(xml::document_t& document);
}; };
class compact_transform : public transform_t { class compact_transform : public transform_t {
// --compact compacts an account tree to remove accounts with only // --compact compacts an account tree to remove accounts with only
// one child account. // one child account.
public: public:
virtual void execute(xml::document_t * document); virtual void execute(xml::document_t& document);
}; };
class clean_transform : public transform_t { class clean_transform : public transform_t {
// --clean clears out entries and accounts that have no contents. // --clean clears out entries and accounts that have no contents.
public: public:
virtual void execute(xml::document_t * document); virtual void execute(xml::document_t& document);
}; };
class entries_transform : public transform_t { class entries_transform : public transform_t {
// --entries transforms the report tree into an entries-wise view. // --entries transforms the report tree into an entries-wise view.
public: public:
virtual void execute(xml::document_t * document); virtual void execute(xml::document_t& document);
}; };
class optimize_transform : public transform_t { class optimize_transform : public transform_t {
@ -79,7 +79,7 @@ class optimize_transform : public transform_t {
// commodity (one the negative of the other), the amount of the // commodity (one the negative of the other), the amount of the
// second transaction will be nulled out. // second transaction will be nulled out.
public: public:
virtual void execute(xml::document_t * document); virtual void execute(xml::document_t& document);
}; };
class split_transform : public transform_t { class split_transform : public transform_t {
@ -89,7 +89,7 @@ class split_transform : public transform_t {
// useful before sorting, for exampel, in order to sort by // useful before sorting, for exampel, in order to sort by
// transaction instead of by entry. // transaction instead of by entry.
public: public:
virtual void execute(xml::document_t * document); virtual void execute(xml::document_t& document);
}; };
class merge_transform : public transform_t { class merge_transform : public transform_t {
@ -97,7 +97,7 @@ class merge_transform : public transform_t {
// which share the same entry will be merged into a group of // which share the same entry will be merged into a group of
// transactions under one reported entry. // transactions under one reported entry.
public: public:
virtual void execute(xml::document_t * document); virtual void execute(xml::document_t& document);
}; };
class combine_transform : public transform_t { class combine_transform : public transform_t {
@ -107,14 +107,14 @@ class combine_transform : public transform_t {
// will show the terminating date or a label that is characteristic // will show the terminating date or a label that is characteristic
// of the set). // of the set).
public: public:
virtual void execute(xml::document_t * document); virtual void execute(xml::document_t& document);
}; };
class group_transform : public transform_t { class group_transform : public transform_t {
// --group groups all transactions that affect the same account // --group groups all transactions that affect the same account
// within an entry, so that they appear as a single transaction. // within an entry, so that they appear as a single transaction.
public: public:
virtual void execute(xml::document_t * document); virtual void execute(xml::document_t& document);
}; };
class collapse_transform : public transform_t { class collapse_transform : public transform_t {
@ -123,7 +123,7 @@ class collapse_transform : public transform_t {
// fictitous account "<total>" is used to represent the final sum, // fictitous account "<total>" is used to represent the final sum,
// if multiple accounts are involved. // if multiple accounts are involved.
public: public:
virtual void execute(xml::document_t * document); virtual void execute(xml::document_t& document);
}; };
class subtotal_transform : public transform_t { class subtotal_transform : public transform_t {
@ -131,7 +131,7 @@ class subtotal_transform : public transform_t {
// one giant entry. When used in conjunction with --group, the // one giant entry. When used in conjunction with --group, the
// affect is very similar to a regular balance report. // affect is very similar to a regular balance report.
public: public:
virtual void execute(xml::document_t * document); virtual void execute(xml::document_t& document);
}; };
#if 0 #if 0
@ -146,7 +146,7 @@ class select_transform : public transform_t
} }
virtual ~select_transform() {} virtual ~select_transform() {}
virtual void execute(xml::document_t * document); virtual void execute(xml::document_t& document);
}; };
class remove_transform : public select_transform class remove_transform : public select_transform
@ -155,7 +155,7 @@ class remove_transform : public select_transform
remove_transform(const string& selection_path) remove_transform(const string& selection_path)
: select_transform(selection_path) {} : select_transform(selection_path) {}
virtual void execute(xml::document_t * document); virtual void execute(xml::document_t& document);
}; };
#endif #endif

File diff suppressed because it is too large Load diff

View file

@ -41,6 +41,7 @@ class xpath_t
{ {
public: public:
struct op_t; struct op_t;
typedef intrusive_ptr<op_t> ptr_op_t;
static void initialize(); static void initialize();
static void shutdown(); static void shutdown();
@ -49,145 +50,24 @@ public:
DECLARE_EXCEPTION(compile_error); DECLARE_EXCEPTION(compile_error);
DECLARE_EXCEPTION(calc_error); DECLARE_EXCEPTION(calc_error);
#if 0
class context : public error_context {
public:
const xpath_t& xpath;
const op_t * err_node;
context(const xpath_t& _xpath,
const op_t * _err_node,
const string& desc = "") throw();
virtual ~context() throw();
virtual void describe(std::ostream& out) const throw();
};
#endif
public: public:
class scope_t; class scope_t;
class functor_t { typedef function<void (value_t&, scope_t *)> function_t;
protected:
string fname;
public:
bool wants_args;
functor_t(const string& _fname, bool _wants_args = false) #define MAKE_FUNCTOR(x) \
: fname(_fname), wants_args(_wants_args) {} xml::xpath_t::wrap_functor(bind(&x, this, _1, _2))
virtual ~functor_t() {}
virtual void operator()(value_t& result, scope_t * locals) = 0; static ptr_op_t wrap_value(const value_t& val);
virtual string name() const { return fname; } static ptr_op_t wrap_sequence(const value_t::sequence_t& val);
}; static ptr_op_t wrap_functor(const function_t& fobj);
template <typename T, typename U>
class member_functor_t : public functor_t {
public:
T * ptr;
U T::*dptr;
member_functor_t(const string& _name, T * _ptr, U T::*_dptr)
: functor_t(_name, false), ptr(_ptr), dptr(_dptr) {}
virtual void operator()(value_t& result, scope_t * locals) {
assert(ptr);
assert(dptr);
result = ptr->*dptr;
}
};
template <typename T>
class member_functor_t<T, string> : public functor_t {
public:
T * ptr;
string T::*dptr;
member_functor_t(const string& _name, T * _ptr, string T::*_dptr)
: functor_t(_name, false), ptr(_ptr), dptr(_dptr) {}
virtual void operator()(value_t& result, scope_t * locals) {
assert(ptr);
assert(dptr);
result.set_string(ptr->*dptr);
}
};
template <typename T>
class memfun_functor_t : public functor_t {
public:
T * ptr;
void (T::*mptr)(value_t& result);
memfun_functor_t(const string& _name, T * _ptr,
void (T::*_mptr)(value_t& result))
: functor_t(_name, false), ptr(_ptr), mptr(_mptr) {}
virtual void operator()(value_t& result, scope_t * locals = NULL) {
assert(ptr);
assert(mptr);
assert(locals || locals == NULL);
(ptr->*mptr)(result);
}
};
template <typename T>
class memfun_args_functor_t : public functor_t {
public:
T * ptr;
void (T::*mptr)(value_t& result, scope_t * locals);
memfun_args_functor_t(const string& _name, T * _ptr,
void (T::*_mptr)(value_t& result, scope_t * locals))
: functor_t(_name, true), ptr(_ptr), mptr(_mptr) {}
virtual void operator()(value_t& result, scope_t * locals) {
assert(ptr);
assert(mptr);
(ptr->*mptr)(result, locals);
}
};
static op_t * wrap_value(const value_t& val);
static op_t * wrap_sequence(const value_t::sequence_t& val);
static op_t * wrap_functor(functor_t * fobj);
#if 0
static op_t * wrap_mask(const string& pattern);
#endif
template <typename T, typename U>
static op_t *
make_functor(const string& name, T * ptr, U T::*mptr) {
return wrap_functor(new member_functor_t<T, U>(name, ptr, mptr));
}
template <typename T>
static op_t *
make_functor(const string& fname, T * ptr,
void (T::*mptr)(value_t& result)) {
return wrap_functor(new memfun_functor_t<T>(fname, ptr, mptr));
}
template <typename T>
static op_t *
make_functor(const string& fname, T * ptr,
void (T::*mptr)(value_t& result, scope_t * locals)) {
return wrap_functor(new memfun_args_functor_t<T>(fname, ptr, mptr));
}
#define MAKE_FUNCTOR(cls, name) \
xml::xpath_t::make_functor(#name, this, &cls::name)
public: public:
class scope_t class scope_t : public noncopyable
{ {
typedef std::map<const string, op_t *> symbol_map; typedef std::map<const string, ptr_op_t> symbol_map;
symbol_map symbols; symbol_map symbols;
scope_t(const scope_t&);
scope_t& operator=(const scope_t&);
public: public:
scope_t * parent; scope_t * parent;
value_t args; value_t args;
@ -201,23 +81,19 @@ public:
virtual ~scope_t() { virtual ~scope_t() {
TRACE_DTOR(xpath_t::scope_t); TRACE_DTOR(xpath_t::scope_t);
for (symbol_map::iterator i = symbols.begin();
i != symbols.end();
i++)
(*i).second->release();
} }
public: public:
virtual void define(const string& name, op_t * def); virtual void define(const string& name, ptr_op_t def);
virtual bool resolve(const string& name, value_t& result, virtual bool resolve(const string& name, value_t& result,
scope_t * locals = NULL) { scope_t * locals = NULL) {
if (parent) if (parent)
return parent->resolve(name, result, locals); return parent->resolve(name, result, locals);
return false; return false;
} }
virtual op_t * lookup(const string& name); virtual ptr_op_t lookup(const string& name);
void define(const string& name, functor_t * def); void define(const string& name, const function_t& def);
friend struct op_t; friend struct op_t;
}; };
@ -225,15 +101,17 @@ public:
class function_scope_t : public scope_t class function_scope_t : public scope_t
{ {
value_t::sequence_t sequence; value_t::sequence_t sequence;
value_t * value; value_t value;
int index; int index;
public: public:
function_scope_t(const value_t::sequence_t& _sequence, function_scope_t(const value_t::sequence_t& _sequence,
value_t * _value, int _index, scope_t * _parent = NULL) value_t * _value, int _index,
scope_t * _parent = NULL)
: scope_t(_parent, STATIC), : scope_t(_parent, STATIC),
sequence(_sequence), value(_value), index(_index) {} sequence(_sequence), value(_value), index(_index) {}
function_scope_t(value_t * _value, int _index, scope_t * _parent = NULL) function_scope_t(const value_t& _value, int _index,
scope_t * _parent = NULL)
: scope_t(_parent, STATIC), value(_value), index(_index) {} : scope_t(_parent, STATIC), value(_value), index(_index) {}
virtual bool resolve(const string& name, value_t& result, virtual bool resolve(const string& name, value_t& result,
@ -245,10 +123,9 @@ public:
#define XPATH_PARSE_RELAXED 0x02 #define XPATH_PARSE_RELAXED 0x02
#define XPATH_PARSE_NO_MIGRATE 0x04 #define XPATH_PARSE_NO_MIGRATE 0x04
#define XPATH_PARSE_NO_REDUCE 0x08 #define XPATH_PARSE_NO_REDUCE 0x08
#if 0 #define XPATH_PARSE_ALLOW_DATE 0x10
#define XPATH_PARSE_REGEXP 0x10
#endif typedef uint_least8_t flags_t;
#define XPATH_PARSE_ALLOW_DATE 0x20
private: private:
struct token_t struct token_t
@ -256,10 +133,6 @@ private:
enum kind_t { enum kind_t {
IDENT, // [A-Za-z_][-A-Za-z0-9_:]* IDENT, // [A-Za-z_][-A-Za-z0-9_:]*
VALUE, // any kind of literal value VALUE, // any kind of literal value
#if 0
REGEXP, // /regexp/ jww (2006-09-24): deprecate
// in favor of a "match" function
#endif
AT_SYM, // @ AT_SYM, // @
DOLLAR, // $ DOLLAR, // $
DOT, // . DOT, // .
@ -286,11 +159,6 @@ private:
QUESTION, // ? QUESTION, // ?
COLON, // : COLON, // :
COMMA, // , COMMA, // ,
#if 0
MATCH, // =~
NMATCH, // !~
PERCENT, // %
#endif
KW_AND, KW_AND,
KW_OR, KW_OR,
KW_DIV, KW_DIV,
@ -336,34 +204,33 @@ private:
} }
void parse_ident(std::istream& in); void parse_ident(std::istream& in);
void next(std::istream& in, unsigned short flags);
void rewind(std::istream& in);
void unexpected();
void next(std::istream& in, flags_t flags);
void rewind(std::istream& in);
void unexpected();
static void unexpected(char c, char wanted = '\0'); static void unexpected(char c, char wanted = '\0');
}; };
public: public:
struct op_t struct op_t : public noncopyable
{ {
enum kind_t { enum kind_t {
VOID, VOID,
VALUE, VALUE,
NODE_NAME,
NODE_ID, NODE_ID,
FUNC_NAME, NODE_NAME,
ATTR_ID,
ATTR_NAME, ATTR_NAME,
FUNC_NAME,
VAR_NAME, VAR_NAME,
ARG_INDEX, ARG_INDEX,
CONSTANTS, // constants end here CONSTANTS, // constants end here
FUNCTOR, FUNCTION,
#if 0
MASK,
#endif
TERMINALS, // terminals end here TERMINALS, // terminals end here
@ -392,19 +259,10 @@ public:
O_COMMA, O_COMMA,
#if 0
O_MATCH,
O_NMATCH,
#endif
O_DEFINE, O_DEFINE,
O_EVAL, O_EVAL,
O_ARG, O_ARG,
#if 0
O_PERC,
#endif
O_FIND, O_FIND,
O_RFIND, O_RFIND,
O_PRED, O_PRED,
@ -414,53 +272,96 @@ public:
kind_t kind; kind_t kind;
mutable short refc; mutable short refc;
op_t * left; ptr_op_t left_;
#if 0 variant<unsigned int, // used by ARG_INDEX and O_ARG
optional<variant<value_t, shared_ptr<value_t>, // used by constant VALUE
string, string, // used by constant SYMBOL
unsigned int, function_t, // used by terminal FUNCTION
functor_t, node_t::nameid_t, // used by NODE_NAME and ATTR_NAME
mask_t, ptr_op_t> // used by all binary operators
op_t> > data; data;
#else
union {
value_t * valuep; // used by constant VALUE
string * name; // used by constant SYMBOL
unsigned int arg_index; // used by ARG_INDEX and O_ARG
functor_t * functor; // used by terminal FUNCTOR
node_t::nameid_t name_id; // used by NODE_NAME and ATTR_NAME
#if 0
mask_t * mask; // used by terminal MASK
#endif
op_t * right; // used by all operators
};
#endif
op_t(const kind_t _kind) op_t(const kind_t _kind) : kind(_kind), refc(0){
: kind(_kind), refc(0), left(NULL), right(NULL) {
TRACE_CTOR(xpath_t::op_t, "const kind_t"); TRACE_CTOR(xpath_t::op_t, "const kind_t");
} }
op_t(const op_t&); ~op_t() {
~op_t(); TRACE_DTOR(xpath_t::op_t);
DEBUG("ledger.xpath.memory", "Destroying " << this);
assert(refc == 0);
}
op_t& operator=(const op_t&); op_t& operator=(const op_t&);
bool constant() const { bool is_value() const {
return kind == VALUE; return kind == VALUE;
} }
void get_value(value_t& result) const;
value_t value() const { unsigned int& as_long() {
value_t temp; assert(kind == ARG_INDEX || kind == O_ARG);
get_value(temp); return boost::get<unsigned int>(data);
return temp; }
const unsigned int& as_long() const {
return const_cast<op_t *>(this)->as_long();
}
void set_long(unsigned int val) {
data = val;
} }
functor_t * functor_obj() const { value_t& as_value() {
if (kind == FUNCTOR) assert(kind == VALUE);
return functor; value_t * val = boost::get<scoped_ptr<value_t> >(data).get();
else assert(val);
return NULL; return *val;
}
const value_t& as_value() const {
return const_cast<op_t *>(this)->as_value();
}
void set_value(value_t * val) {
// jww (2007-05-14): Ugh, fix this
data = shared_ptr<value_t>(val);
}
string& as_string() {
assert(kind == NODE_NAME || kind == ATTR_NAME || kind == FUNC_NAME);
return boost::get<string>(data);
}
const string& as_string() const {
return const_cast<op_t *>(this)->as_string();
}
void set_string(const string& val) {
data = val;
}
function_t& as_function() {
assert(kind == FUNCTION);
return boost::get<function_t>(data);
}
const function_t& as_function() const {
return const_cast<op_t *>(this)->as_function();
}
void set_function(const function_t& val) {
data = val;
}
node_t::nameid_t& as_name() {
assert(kind == NODE_ID || kind == ATTR_ID);
return boost::get<node_t::nameid_t>(data);
}
const node_t::nameid_t& as_name() const {
return const_cast<op_t *>(this)->as_name();
}
void set_name(const node_t::nameid_t& val) {
data = val;
}
ptr_op_t& as_op() {
assert(kind > TERMINALS);
return boost::get<ptr_op_t>(data);
}
const ptr_op_t& as_op() const {
return const_cast<op_t *>(this)->as_op();
} }
void release() const { void release() const {
@ -470,54 +371,55 @@ public:
if (--refc == 0) if (--refc == 0)
checked_delete(this); checked_delete(this);
} }
op_t * acquire() { void acquire() {
DEBUG("ledger.xpath.memory", DEBUG("ledger.xpath.memory",
"Acquiring " << this << ", refc now " << refc + 1); "Acquiring " << this << ", refc now " << refc + 1);
assert(refc >= 0); assert(refc >= 0);
refc++; refc++;
return this;
}
const op_t * acquire() const {
DEBUG("ledger.xpath.memory",
"Acquiring " << this << ", refc now " << refc + 1);
assert(refc >= 0);
refc++;
return this;
} }
void set_left(op_t * expr) { ptr_op_t& left() {
return left_;
}
const ptr_op_t& left() const {
assert(kind > TERMINALS); assert(kind > TERMINALS);
if (left) return left_;
left->release();
left = expr ? expr->acquire() : NULL;
} }
void set_left(const ptr_op_t& expr) {
void set_right(op_t * expr) {
assert(kind > TERMINALS); assert(kind > TERMINALS);
if (right) left_ = expr;
right->release();
right = expr ? expr->acquire() : NULL;
} }
static op_t * new_node(kind_t kind, op_t * left = NULL, ptr_op_t& right() {
op_t * right = NULL); assert(kind > TERMINALS);
return as_op();
}
const ptr_op_t& right() const {
assert(kind > TERMINALS);
return as_op();
}
void set_right(const ptr_op_t& expr) {
assert(kind > TERMINALS);
data = expr;
}
op_t * copy(op_t * left = NULL, static ptr_op_t new_node(kind_t kind, ptr_op_t left = NULL,
op_t * right = NULL) const; ptr_op_t right = NULL);
op_t * compile(value_t * context, scope_t * scope,
bool resolve = false);
void find_values(value_t * context, scope_t * scope, ptr_op_t copy(ptr_op_t left = NULL, ptr_op_t right = NULL) const;
ptr_op_t compile(value_t& context, scope_t * scope, bool resolve = false);
void find_values(value_t& context, scope_t * scope,
value_t::sequence_t& result_seq, bool recursive); value_t::sequence_t& result_seq, bool recursive);
bool test_value(value_t * context, scope_t * scope, int index = 0); bool test_value(value_t& context, scope_t * scope, int index = 0);
void append_value(value_t& value, value_t::sequence_t& result_seq); void append_value(value_t& value, value_t::sequence_t& result_seq);
static op_t * defer_sequence(value_t::sequence_t& result_seq); static ptr_op_t defer_sequence(value_t::sequence_t& result_seq);
bool print(std::ostream& out, bool print(std::ostream& out,
const bool relaxed = true, const bool relaxed = true,
const op_t * op_to_find = NULL, const ptr_op_t& op_to_find = NULL,
unsigned long * start_pos = NULL, unsigned long * start_pos = NULL,
unsigned long * end_pos = NULL) const; unsigned long * end_pos = NULL) const;
@ -525,44 +427,14 @@ public:
}; };
public: public:
op_t * ptr; ptr_op_t ptr;
xpath_t& operator=(op_t * _expr) { xpath_t& operator=(ptr_op_t _expr) {
expr = ""; expr = "";
reset(_expr); ptr = _expr;
return *this; return *this;
} }
op_t& operator*() throw() {
return *ptr;
}
const op_t& operator*() const throw() {
return *ptr;
}
op_t * operator->() throw() {
return ptr;
}
const op_t * operator->() const throw() {
return ptr;
}
op_t * get() throw() { return ptr; }
const op_t * get() const throw() { return ptr; }
op_t * release() throw() {
op_t * tmp = ptr;
ptr = 0;
return tmp;
}
void reset(op_t * p = 0) throw() {
if (p != ptr) {
if (ptr)
ptr->release();
ptr = p;
}
}
#ifdef THREADSAFE #ifdef THREADSAFE
mutable token_t lookahead; mutable token_t lookahead;
#else #else
@ -570,7 +442,7 @@ public:
#endif #endif
mutable bool use_lookahead; mutable bool use_lookahead;
token_t& next_token(std::istream& in, unsigned short tflags) const { token_t& next_token(std::istream& in, flags_t tflags) const {
if (use_lookahead) if (use_lookahead)
use_lookahead = false; use_lookahead = false;
else else
@ -597,24 +469,24 @@ public:
use_lookahead = true; use_lookahead = true;
} }
op_t * parse_value_term(std::istream& in, unsigned short flags) const; ptr_op_t parse_value_term(std::istream& in, flags_t flags) const;
op_t * parse_predicate_expr(std::istream& in, unsigned short flags) const; ptr_op_t parse_predicate_expr(std::istream& in, flags_t flags) const;
op_t * parse_path_expr(std::istream& in, unsigned short flags) const; ptr_op_t parse_path_expr(std::istream& in, flags_t flags) const;
op_t * parse_unary_expr(std::istream& in, unsigned short flags) const; ptr_op_t parse_unary_expr(std::istream& in, flags_t flags) const;
op_t * parse_union_expr(std::istream& in, unsigned short flags) const; ptr_op_t parse_union_expr(std::istream& in, flags_t flags) const;
op_t * parse_mul_expr(std::istream& in, unsigned short flags) const; ptr_op_t parse_mul_expr(std::istream& in, flags_t flags) const;
op_t * parse_add_expr(std::istream& in, unsigned short flags) const; ptr_op_t parse_add_expr(std::istream& in, flags_t flags) const;
op_t * parse_logic_expr(std::istream& in, unsigned short flags) const; ptr_op_t parse_logic_expr(std::istream& in, flags_t flags) const;
op_t * parse_and_expr(std::istream& in, unsigned short flags) const; ptr_op_t parse_and_expr(std::istream& in, flags_t flags) const;
op_t * parse_or_expr(std::istream& in, unsigned short flags) const; ptr_op_t parse_or_expr(std::istream& in, flags_t flags) const;
op_t * parse_querycolon_expr(std::istream& in, unsigned short flags) const; ptr_op_t parse_querycolon_expr(std::istream& in, flags_t flags) const;
op_t * parse_value_expr(std::istream& in, unsigned short flags) const; ptr_op_t parse_value_expr(std::istream& in, flags_t flags) const;
op_t * parse_expr(std::istream& in, ptr_op_t parse_expr(std::istream& in,
unsigned short flags = XPATH_PARSE_RELAXED) const; flags_t flags = XPATH_PARSE_RELAXED) const;
op_t * parse_expr(const string& str, ptr_op_t parse_expr(const string& str,
unsigned short tflags = XPATH_PARSE_RELAXED) const flags_t tflags = XPATH_PARSE_RELAXED) const
{ {
std::istringstream stream(str); std::istringstream stream(str);
#if 0 #if 0
@ -632,14 +504,14 @@ public:
#endif #endif
} }
op_t * parse_expr(const char * p, ptr_op_t parse_expr(const char * p,
unsigned short tflags = XPATH_PARSE_RELAXED) const { flags_t tflags = XPATH_PARSE_RELAXED) const {
return parse_expr(string(p), tflags); return parse_expr(string(p), tflags);
} }
bool print(std::ostream& out, bool print(std::ostream& out,
const bool relaxed, const bool relaxed,
const op_t * op_to_find, const ptr_op_t op_to_find,
unsigned long * start_pos, unsigned long * start_pos,
unsigned long * end_pos) const { unsigned long * end_pos) const {
if (ptr) if (ptr)
@ -648,36 +520,34 @@ public:
} }
public: public:
string expr; string expr;
unsigned short flags; // flags used to parse `expr' flags_t flags; // flags used to parse `expr'
xpath_t() : ptr(NULL), use_lookahead(false), flags(0) { xpath_t() : ptr(NULL), use_lookahead(false), flags(0) {
TRACE_CTOR(xpath_t, ""); TRACE_CTOR(xpath_t, "");
} }
xpath_t(op_t * _ptr) : ptr(_ptr), use_lookahead(false) { xpath_t(ptr_op_t _ptr) : ptr(_ptr), use_lookahead(false) {
TRACE_CTOR(xpath_t, "op_t *"); TRACE_CTOR(xpath_t, "ptr_op_t");
} }
xpath_t(const string& _expr, xpath_t(const string& _expr, flags_t _flags = XPATH_PARSE_RELAXED)
unsigned short _flags = XPATH_PARSE_RELAXED)
: ptr(NULL), use_lookahead(false), flags(0) { : ptr(NULL), use_lookahead(false), flags(0) {
TRACE_CTOR(xpath_t, "const string&, unsigned short"); TRACE_CTOR(xpath_t, "const string&, flags_t");
if (! _expr.empty()) if (! _expr.empty())
parse(_expr, _flags); parse(_expr, _flags);
} }
xpath_t(std::istream& in, unsigned short _flags = XPATH_PARSE_RELAXED) xpath_t(std::istream& in, flags_t _flags = XPATH_PARSE_RELAXED)
: ptr(NULL), use_lookahead(false), flags(0) { : ptr(NULL), use_lookahead(false), flags(0) {
TRACE_CTOR(xpath_t, "std::istream&, unsigned short"); TRACE_CTOR(xpath_t, "std::istream&, flags_t");
parse(in, _flags); parse(in, _flags);
} }
xpath_t(const xpath_t& other) xpath_t(const xpath_t& other)
: ptr(other.ptr ? other.ptr->acquire() : NULL), : ptr(other.ptr), use_lookahead(false),
use_lookahead(false), expr(other.expr), flags(other.flags) { expr(other.expr), flags(other.flags) {
TRACE_CTOR(xpath_t, "copy"); TRACE_CTOR(xpath_t, "copy");
} }
virtual ~xpath_t() { virtual ~xpath_t() {
TRACE_DTOR(xpath_t); TRACE_DTOR(xpath_t);
reset(NULL);
} }
xpath_t& operator=(const string& _expr) { xpath_t& operator=(const string& _expr) {
@ -686,14 +556,14 @@ public:
} }
xpath_t& operator=(const xpath_t& _expr); xpath_t& operator=(const xpath_t& _expr);
xpath_t& operator=(xpath_t& _xpath) { xpath_t& operator=(xpath_t& _xpath) {
ptr = _xpath.ptr->acquire(); ptr = _xpath.ptr;
expr = _xpath.expr; expr = _xpath.expr;
flags = _xpath.flags; flags = _xpath.flags;
use_lookahead = false; use_lookahead = false;
return *this; return *this;
} }
operator op_t *() throw() { operator ptr_op_t() throw() {
return ptr; return ptr;
} }
@ -704,29 +574,21 @@ public:
return expr; return expr;
} }
void parse(const string& _expr, unsigned short _flags = XPATH_PARSE_RELAXED) { void parse(const string& _expr, flags_t _flags = XPATH_PARSE_RELAXED) {
expr = _expr; expr = _expr;
flags = _flags; flags = _flags;
op_t * tmp = parse_expr(_expr, _flags); ptr = parse_expr(_expr, _flags);
assert(tmp);
reset(tmp ? tmp->acquire() : NULL);
} }
void parse(std::istream& in, unsigned short _flags = XPATH_PARSE_RELAXED) { void parse(std::istream& in, flags_t _flags = XPATH_PARSE_RELAXED) {
expr = ""; expr = "";
flags = _flags; flags = _flags;
op_t * tmp = parse_expr(in, _flags); ptr = parse_expr(in, _flags);
assert(tmp);
reset(tmp ? tmp->acquire() : NULL);
} }
void compile(node_t& top_node, scope_t * scope = NULL) { void compile(node_t& top_node, scope_t * scope = NULL) {
if (ptr) { if (ptr.get()) {
value_t noderef(&top_node); value_t noderef(&top_node);
op_t * compiled = ptr->compile(&noderef, scope); ptr = ptr->compile(noderef, scope);
if (compiled == ptr)
compiled->release();
else
reset(compiled);
} }
} }
@ -767,6 +629,13 @@ inline std::ostream& operator<<(std::ostream& out, const xpath_t::op_t& op) {
return out; return out;
} }
inline void intrusive_ptr_add_ref(xpath_t::op_t * op) {
op->acquire();
}
inline void intrusive_ptr_release(xpath_t::op_t * op) {
op->release();
}
} // namespace xml } // namespace xml
template <typename T> template <typename T>
@ -777,15 +646,20 @@ inline T * get_ptr(xml::xpath_t::scope_t * locals, unsigned int idx) {
return ptr; return ptr;
} }
class xml_command : public xml::xpath_t::functor_t template <typename T>
inline T * get_node_ptr(xml::xpath_t::scope_t * locals, unsigned int idx) {
assert(locals->args.size() > idx);
T * ptr = polymorphic_downcast<T *>(locals->args[idx].as_xml_node());
assert(ptr);
return ptr;
}
class xml_command
{ {
public: public:
xml_command() : xml::xpath_t::functor_t("xml") {} void operator()(value_t&, xml::xpath_t::scope_t * locals) {
virtual void operator()(value_t&, xml::xpath_t::scope_t * locals) {
std::ostream * out = get_ptr<std::ostream>(locals, 0); std::ostream * out = get_ptr<std::ostream>(locals, 0);
xml::document_t * doc = get_ptr<xml::document_t>(locals, 1); xml::document_t * doc = get_node_ptr<xml::document_t>(locals, 1);
doc->print(*out); doc->print(*out);
} }
}; };