A large body of work to get the register report printing again, but still

fails due to the fact that 2.x value expression syntax is not restored.
This commit is contained in:
John Wiegley 2008-07-27 00:10:35 -04:00
parent 162d982b0c
commit 713f896790
19 changed files with 1069 additions and 456 deletions

View file

@ -906,7 +906,7 @@ namespace {
}
}
void amount_t::parse(std::istream& in, flags_t flags)
bool amount_t::parse(std::istream& in, flags_t flags)
{
// The possible syntax for an amount is:
//
@ -957,8 +957,12 @@ void amount_t::parse(std::istream& in, flags_t flags)
}
}
if (quant.empty())
throw_(amount_error, "No quantity specified for amount");
if (quant.empty()) {
if (flags & AMOUNT_PARSE_SOFT_FAIL)
return false;
else
throw_(amount_error, "No quantity specified for amount");
}
// Allocate memory for the amount's quantity value. We have to
// monitor the allocation in an auto_ptr because this function gets
@ -1069,6 +1073,8 @@ void amount_t::parse(std::istream& in, flags_t flags)
safe_holder.release(); // `this->quantity' owns the pointer
assert(valid());
return true;
}
void amount_t::parse_conversion(const string& larger_str,

View file

@ -590,16 +590,18 @@ public:
* amount_t::parse_conversion("1.0m", "60s"); // a minute is 60 seconds
* amount_t::parse_conversion("1.0h", "60m"); // an hour is 60 minutes
*/
#define AMOUNT_PARSE_NO_MIGRATE 0x01
#define AMOUNT_PARSE_NO_REDUCE 0x02
#define AMOUNT_PARSE_NO_MIGRATE 0x01
#define AMOUNT_PARSE_NO_REDUCE 0x02
#define AMOUNT_PARSE_SOFT_FAIL 0x04
typedef uint_least8_t flags_t;
void parse(std::istream& in, flags_t flags = 0);
void parse(const string& str, flags_t flags = 0) {
bool parse(std::istream& in, flags_t flags = 0);
bool parse(const string& str, flags_t flags = 0) {
std::istringstream stream(str);
parse(stream, flags);
bool result = parse(stream, flags);
assert(stream.eof());
return result;
}
static void parse_conversion(const string& larger_str,

View file

@ -564,8 +564,6 @@ account_t * read_account(const char *& data, journal_t& journal,
account_t * acct = new account_t(NULL);
*accounts_next++ = acct;
acct->journal = &journal;
account_t::ident_t id;
read_long(data, id); // parent id
if (id == 0xffffffff)

View file

@ -1,14 +1,15 @@
#include "derive.h"
#include "utils.h"
#include "mask.h"
#include "session.h"
#include "walk.h"
namespace ledger {
entry_t * derive_new_entry(journal_t& journal,
entry_t * derive_new_entry(report_t& report,
strings_list::iterator i,
strings_list::iterator end)
{
session_t& session(report.session);
std::auto_ptr<entry_t> added(new entry_t);
entry_t * matching = NULL;
@ -21,26 +22,32 @@ entry_t * derive_new_entry(journal_t& journal,
mask_t regexp(*i++);
journals_iterator iter(session);
entries_list::reverse_iterator j;
for (j = journal.entries.rbegin();
j != journal.entries.rend();
j++)
if (regexp.match((*j)->payee)) {
matching = *j;
break;
for (journal_t * journal = iter(); journal; journal = iter()) {
for (j = journal->entries.rbegin();
j != journal->entries.rend();
j++) {
if (regexp.match((*j)->payee)) {
matching = *j;
break;
}
}
if (matching) break;
}
added->payee = matching ? matching->payee : regexp.expr.str();
if (! matching) {
account_t * acct;
if (i == end || ((*i)[0] == '-' || std::isdigit((*i)[0]))) {
acct = journal.find_account("Expenses");
acct = session.find_account("Expenses");
}
else if (i != end) {
acct = journal.find_account_re(*i);
acct = session.find_account_re(*i);
if (! acct)
acct = journal.find_account(*i);
acct = session.find_account(*i);
assert(acct);
i++;
}
@ -58,12 +65,7 @@ entry_t * derive_new_entry(journal_t& journal,
// account to which only dollars are applied would imply that
// dollars are wanted now too.
std::auto_ptr<item_handler<transaction_t> > formatter;
formatter.reset(new set_account_value);
walk_entries(journal.entries, *formatter.get());
formatter->flush();
sum_accounts(*journal.master);
report.sum_all_accounts();
value_t total = account_xdata(*acct).total;
if (total.is_type(value_t::AMOUNT))
@ -75,16 +77,16 @@ entry_t * derive_new_entry(journal_t& journal,
if (i != end) {
if (! acct)
acct = journal.find_account_re(*i);
acct = session.find_account_re(*i);
if (! acct)
acct = journal.find_account(*i);
acct = session.find_account(*i);
}
if (! acct) {
if (journal.basket)
acct = journal.basket;
if (matching && matching->journal->basket)
acct = matching->journal->basket;
else
acct = journal.find_account("Equity");
acct = session.find_account("Equity");
}
added->add_transaction(new transaction_t(acct));
@ -115,9 +117,9 @@ entry_t * derive_new_entry(journal_t& journal,
added->add_transaction(xact);
if (i != end) {
account_t * acct = journal.find_account_re(*i);
account_t * acct = session.find_account_re(*i);
if (! acct)
acct = journal.find_account(*i);
acct = session.find_account(*i);
assert(acct);
added->transactions.back()->account = acct;
}
@ -132,7 +134,7 @@ entry_t * derive_new_entry(journal_t& journal,
mask_t acct_regex(re_pat);
for (; j != journal.entries.rend(); j++)
for (; j != matching->journal->entries.rend(); j++)
if (regexp.match((*j)->payee)) {
entry_t * entry = *j;
for (transactions_list::const_iterator x =
@ -159,16 +161,16 @@ entry_t * derive_new_entry(journal_t& journal,
strings_list::iterator x = i;
if (i != end && ++x == end) {
draw_acct = journal.find_account_re(*i);
draw_acct = session.find_account_re(*i);
if (! draw_acct)
draw_acct = journal.find_account(*i);
draw_acct = session.find_account(*i);
i++;
}
if (! acct)
acct = journal.find_account_re(re_pat);
acct = session.find_account_re(re_pat);
if (! acct)
acct = journal.find_account(re_pat);
acct = session.find_account(re_pat);
xact = new transaction_t(acct, amount);
if (! xact->amount.commodity()) {
@ -189,9 +191,11 @@ entry_t * derive_new_entry(journal_t& journal,
added->add_transaction(new transaction_t(draw_acct));
}
if (! run_hooks(journal.entry_finalize_hooks, *added, false) ||
if ((matching &&
! run_hooks(matching->journal->entry_finalize_hooks, *added, false)) ||
! added->finalize() ||
! run_hooks(journal.entry_finalize_hooks, *added, true))
(matching &&
! run_hooks(matching->journal->entry_finalize_hooks, *added, true)))
throw new error("Failed to finalize derived entry (check commodities)");
return added.release();

View file

@ -1,11 +1,11 @@
#ifndef _DERIVE_H
#define _DERIVE_H
#include "journal.h"
#include "report.h"
namespace ledger {
entry_t * derive_new_entry(journal_t& journal,
entry_t * derive_new_entry(report_t& report,
strings_list::iterator begin,
strings_list::iterator end);

View file

@ -850,6 +850,7 @@ void print_entry(std::ostream& out, const entry_base_t& entry_base,
assert(false);
}
#if 0
format_entries formatter(out, print_format);
walk_transactions(const_cast<transactions_list&>(entry_base.transactions),
formatter);
@ -858,6 +859,7 @@ void print_entry(std::ostream& out, const entry_base_t& entry_base,
clear_transaction_xdata cleaner;
walk_transactions(const_cast<transactions_list&>(entry_base.transactions),
cleaner);
#endif
}
bool disp_subaccounts_p(const account_t& account,
@ -918,7 +920,7 @@ bool display_account(const account_t& account,
return ! account_to_show && (! disp_pred || (*disp_pred)(account));
}
void format_account::operator()(account_t& account)
void format_accounts::operator()(account_t& account)
{
if (display_account(account, disp_pred)) {
if (! account.parent) {

View file

@ -173,7 +173,7 @@ inline bool disp_subaccounts_p(const account_t& account) {
bool display_account(const account_t& account,
const optional<item_predicate<account_t> >& disp_pred);
class format_account : public item_handler<account_t>
class format_accounts : public item_handler<account_t>
{
std::ostream& output_stream;
@ -182,15 +182,15 @@ class format_account : public item_handler<account_t>
public:
format_t format;
format_account(std::ostream& _output_stream,
const string& _format,
const string& display_predicate = NULL)
format_accounts(std::ostream& _output_stream,
const string& _format,
const string& display_predicate = NULL)
: output_stream(_output_stream), disp_pred(display_predicate),
format(_format) {
TRACE_CTOR(format_account, "std::ostream&, const string&, const string&");
TRACE_CTOR(format_accounts, "std::ostream&, const string&, const string&");
}
~format_account() throw() {
TRACE_DTOR(format_account);
~format_accounts() throw() {
TRACE_DTOR(format_accounts);
}
virtual void flush() {
@ -211,7 +211,7 @@ class format_equity : public item_handler<account_t>
mutable value_t total;
public:
format_equity(std::ostream& _output_stream,
format_equity(std::ostream& _output_stream,
const string& _format,
const string& display_predicate);

View file

@ -30,10 +30,8 @@
*/
#include "journal.h"
#include "utils.h"
#include "valexpr.h"
#include "format.h"
#include "mask.h"
#include "session.h"
namespace ledger {
@ -520,8 +518,6 @@ account_t * account_t::find_account(const string& name,
return NULL;
account = new account_t(this, first);
account->journal = journal;
std::pair<accounts_map::iterator, bool> result
= accounts.insert(accounts_map::value_type(first, account));
assert(result.second);
@ -535,26 +531,6 @@ account_t * account_t::find_account(const string& name,
return account;
}
static inline
account_t * find_account_re_(account_t * account, const mask_t& regexp)
{
if (regexp.match(account->fullname()))
return account;
for (accounts_map::iterator i = account->accounts.begin();
i != account->accounts.end();
i++)
if (account_t * a = find_account_re_((*i).second, regexp))
return a;
return NULL;
}
account_t * journal_t::find_account_re(const string& regexp)
{
return find_account_re_(master, mask_t(regexp));
}
string account_t::fullname() const
{
if (! _fullname.empty()) {
@ -583,8 +559,8 @@ std::ostream& operator<<(std::ostream& out, const account_t& account)
bool account_t::valid() const
{
if (depth > 256 || ! journal) {
DEBUG("ledger.validate", "account_t: depth > 256 || ! journal");
if (depth > 256) {
DEBUG("ledger.validate", "account_t: depth > 256");
return false;
}
@ -605,13 +581,17 @@ bool account_t::valid() const
return true;
}
journal_t::journal_t(session_t * _owner) :
owner(_owner), basket(NULL), item_pool(NULL), item_pool_end(NULL)
{
TRACE_CTOR(journal_t, "");
master = owner->master;
}
journal_t::~journal_t()
{
TRACE_DTOR(journal_t);
assert(master);
checked_delete(master);
// Don't bother unhooking each entry's transactions from the
// accounts they refer to, because all accounts are about to
// be deleted.
@ -651,6 +631,26 @@ journal_t::~journal_t()
checked_array_delete(item_pool);
}
void journal_t::add_account(account_t * acct)
{
owner->add_account(acct);
}
bool journal_t::remove_account(account_t * acct)
{
return owner->remove_account(acct);
}
account_t * journal_t::find_account(const string& name, bool auto_create)
{
return owner->find_account(name, auto_create);
}
account_t * journal_t::find_account_re(const string& regexp)
{
return owner->find_account_re(regexp);
}
bool journal_t::add_entry(entry_t * entry)
{
entry->journal = this;

View file

@ -339,7 +339,6 @@ class account_t
public:
typedef unsigned long ident_t;
journal_t * journal;
account_t * parent;
string name;
optional<string> note;
@ -358,8 +357,7 @@ class account_t
TRACE_CTOR(account_t, "account_t *, const string&, const string&");
}
account_t(const account_t& other)
: journal(other.journal),
parent(other.parent),
: parent(other.parent),
name(other.name),
note(other.note),
depth(other.depth),
@ -379,11 +377,9 @@ class account_t
void add_account(account_t * acct) {
accounts.insert(accounts_map::value_type(acct->name, acct));
acct->journal = journal;
}
bool remove_account(account_t * acct) {
accounts_map::size_type n = accounts.erase(acct->name);
acct->journal = NULL;
return n > 0;
}
@ -468,37 +464,17 @@ class journal_t : public noncopyable
auto_entries_list auto_entries;
period_entries_list period_entries;
mutable accounts_map accounts_cache;
std::list<entry_finalizer_t *> entry_finalize_hooks;
journal_t(session_t * _owner) :
owner(_owner), basket(NULL), item_pool(NULL), item_pool_end(NULL) {
TRACE_CTOR(journal_t, "");
master = new account_t(NULL, "");
master->journal = this;
}
journal_t(session_t * _owner);
~journal_t();
void add_account(account_t * acct) {
master->add_account(acct);
acct->journal = this;
}
bool remove_account(account_t * acct) {
return master->remove_account(acct);
acct->journal = NULL;
}
account_t * find_account(const string& name, bool auto_create = true) {
accounts_map::iterator c = accounts_cache.find(name);
if (c != accounts_cache.end())
return (*c).second;
account_t * account = master->find_account(name, auto_create);
accounts_cache.insert(accounts_map::value_type(name, account));
account->journal = this;
return account;
}
// These four methods are delegated to 'owner', since all accounts processed
// are gathered together at the session level.
void add_account(account_t * acct);
bool remove_account(account_t * acct);
account_t * find_account(const string& name, bool auto_create = true);
account_t * find_account_re(const string& regexp);
bool add_entry(entry_t * entry);

257
main.cc
View file

@ -45,17 +45,6 @@
#include <fdstream.hpp>
#endif
namespace ledger {
value_t register_command(expr::call_scope_t& args)
{
expr::var_t<std::ostream> ostream(args, "ostream");
*ostream << "This (will be) the register command.\n";
return true;
}
}
static int read_and_report(ledger::report_t& report, int argc, char * argv[],
char * envp[])
{
@ -114,113 +103,6 @@ static int read_and_report(ledger::report_t& report, int argc, char * argv[],
if (! session.use_cache)
INFO("Binary cache mechanism will not be used");
// Read the command word and create a command object based on it
string verb = *arg++;
expr::function_t command;
if (verb == "register" || verb == "reg" || verb == "r")
command = register_command;
#if 0
else if (verb == "balance" || verb == "bal" || verb == "b")
command = balance_command();
else if (verb == "print" || verb == "p")
command = print_command();
else if (verb == "equity")
command = equity_command();
else if (verb == "entry")
command = entry_command();
else if (verb == "dump")
command = dump_command();
else if (verb == "output")
command = output_command();
else if (verb == "prices")
command = prices_command();
else if (verb == "pricesdb")
command = pricesdb_command();
else if (verb == "csv")
command = csv_command();
else if (verb == "emacs" || verb == "lisp")
command = emacs_command();
else if (verb == "xml")
command = bind(xml_command, _1);
;
#endif
else if (verb == "expr")
;
else if (verb == "xpath")
;
else if (verb == "parse") {
value_expr expr(*arg);
#if 0
expr::context_scope_t doc_scope(report, &temp);
IF_INFO() {
std::cout << "Value expression tree:" << std::endl;
expr.dump(std::cout);
std::cout << std::endl;
std::cout << "Value expression parsed was:" << std::endl;
expr.print(std::cout, doc_scope);
std::cout << std::endl << std::endl;
expr.compile(doc_scope);
std::cout << "Value expression after compiling:" << std::endl;
expr.dump(std::cout);
std::cout << std::endl;
std::cout << "Value expression is now:" << std::endl;
expr.print(std::cout, doc_scope);
std::cout << std::endl << std::endl;
std::cout << "Result of calculation: ";
}
std::cout << expr.calc(doc_scope).strip_annotations() << std::endl;
#endif
return 0;
}
else {
char buf[128];
std::strcpy(buf, "command_");
std::strcat(buf, verb.c_str());
if (expr::ptr_op_t def = report.lookup(buf))
command = def->as_function();
if (! command)
throw_(std::logic_error, string("Unrecognized command '") + verb + "'");
}
// Parse the initialization file, which can only be textual; then
// parse the journal data.
session.read_init();
INFO_START(journal, "Read journal file");
journal_t& journal(*session.create_journal());
std::size_t count = session.read_data(journal, report.account);
if (count == 0)
throw_(parse_error, "Failed to locate any journal entries; "
"did you specify a valid file with -f?");
INFO_FINISH(journal);
INFO("Found " << count << " entries");
TRACE_FINISH(entry_text, 1);
TRACE_FINISH(entry_date, 1);
TRACE_FINISH(entry_details, 1);
TRACE_FINISH(entry_xacts, 1);
TRACE_FINISH(entries, 1);
TRACE_FINISH(parsing_total, 1);
// Configure the output stream
#ifdef HAVE_UNIX_PIPES
@ -268,7 +150,68 @@ static int read_and_report(ledger::report_t& report, int argc, char * argv[],
}
#endif
report.define("ostream", value_t(out));
// Read the command word and create a command object based on it
string verb = *arg++;
if (verb == "parse") {
value_expr expr(*arg);
#if 0
expr::context_scope_t doc_scope(report, &temp);
IF_INFO() {
std::cout << "Value expression tree:" << std::endl;
expr.dump(std::cout);
std::cout << std::endl;
std::cout << "Value expression parsed was:" << std::endl;
expr.print(std::cout, doc_scope);
std::cout << std::endl << std::endl;
expr.compile(doc_scope);
std::cout << "Value expression after compiling:" << std::endl;
expr.dump(std::cout);
std::cout << std::endl;
std::cout << "Value expression is now:" << std::endl;
expr.print(std::cout, doc_scope);
std::cout << std::endl << std::endl;
std::cout << "Result of calculation: ";
}
std::cout << expr.calc(doc_scope).strip_annotations() << std::endl;
#endif
return 0;
}
// Parse the initialization file, which can only be textual; then
// parse the journal data.
session.read_init();
INFO_START(journal, "Read journal file");
journal_t& journal(*session.create_journal());
std::size_t count = session.read_data(journal, report.account);
if (count == 0)
throw_(parse_error, "Failed to locate any journal entries; "
"did you specify a valid file with -f?");
INFO_FINISH(journal);
INFO("Found " << count << " entries");
TRACE_FINISH(entry_text, 1);
TRACE_FINISH(entry_date, 1);
TRACE_FINISH(entry_details, 1);
TRACE_FINISH(entry_xacts, 1);
TRACE_FINISH(entries, 1);
TRACE_FINISH(parsing_total, 1);
// Are we handling the expr commands? Do so now.
@ -294,11 +237,52 @@ static int read_and_report(ledger::report_t& report, int argc, char * argv[],
return 0;
}
// Apply transforms to the hierarchical document structure
// Read the command word and create a command object based on it
INFO_START(transforms, "Applied transforms");
report.apply_transforms(*expr::global_scope);
INFO_FINISH(transforms);
if (verb == "register" || verb == "reg" || verb == "r")
report.transactions_report
(xact_handler_ptr(new format_transactions(*out, session.register_format)));
else if (verb == "balance" || verb == "bal" || verb == "b")
report.accounts_report
(acct_handler_ptr(new format_accounts(*out, session.balance_format,
report.display_predicate)));
#if 0
else if (verb == "print" || verb == "p")
command = print_command();
else if (verb == "equity")
command = equity_command();
else if (verb == "entry")
command = entry_command();
else if (verb == "dump")
command = dump_command();
else if (verb == "output")
command = output_command();
else if (verb == "prices")
command = prices_command();
else if (verb == "pricesdb")
command = pricesdb_command();
else if (verb == "csv")
command = csv_command();
else if (verb == "emacs" || verb == "lisp")
command = emacs_command();
else if (verb == "xml")
command = bind(xml_command, _1);
;
else if (verb == "expr")
;
else if (verb == "xpath")
;
else {
char buf[128];
std::strcpy(buf, "command_");
std::strcat(buf, verb.c_str());
if (expr::ptr_op_t def = report.lookup(buf))
command = def->as_function();
if (! command)
throw_(std::logic_error, string("Unrecognized command '") + verb + "'");
}
// Create an argument scope containing the report command's
// arguments, and then invoke the command.
@ -313,31 +297,12 @@ static int read_and_report(ledger::report_t& report, int argc, char * argv[],
command(command_args);
INFO_FINISH(command);
// Clean up memory, if we
if (DO_VERIFY()) {
TRACE_START(cleanup, 1, "Cleaning up allocated memory");
clear_transaction_xdata xact_cleaner;
walk_entries(journal.entries, xact_cleaner);
clear_account_xdata acct_cleaner;
walk_accounts(*journal.master, acct_cleaner);
if (report.output_file)
checked_delete(out);
#if 0
for (std::list<item_handler<transaction_t> *>::iterator i
= formatter_ptrs.begin();
i != formatter_ptrs.end();
i++)
checked_delete(*i);
#endif
TRACE_FINISH(cleanup, 1);
}
// Clean up memory, if it matters
if (DO_VERIFY() && report.output_file)
checked_delete(out);
// Write out the binary cache, if need be

View file

@ -388,35 +388,27 @@ void parser_t::token_t::next(std::istream& in, const flags_t flags)
// When in relaxed parsing mode, we want to migrate commodity
// flags so that any precision specified by the user updates the
// current maximum displayed precision.
try {
pos = (long)in.tellg();
pos = (long)in.tellg();
unsigned char parse_flags = 0;
if (flags & EXPR_PARSE_NO_MIGRATE)
parse_flags |= AMOUNT_PARSE_NO_MIGRATE;
if (flags & EXPR_PARSE_NO_REDUCE)
parse_flags |= AMOUNT_PARSE_NO_REDUCE;
unsigned char parse_flags = 0;
if (flags & EXPR_PARSE_NO_MIGRATE)
parse_flags |= AMOUNT_PARSE_NO_MIGRATE;
if (flags & EXPR_PARSE_NO_REDUCE)
parse_flags |= AMOUNT_PARSE_NO_REDUCE;
temp.parse(in, parse_flags);
kind = VALUE;
value = temp;
}
catch (const amount_error& err) {
if (! temp.parse(in, parse_flags | AMOUNT_PARSE_SOFT_FAIL)) {
// If the amount had no commodity, it must be an unambiguous
// variable reference
// jww (2007-04-19): There must be a more efficient way to do this!
if (std::strcmp(err.what(), "No quantity specified for amount") == 0) {
in.clear();
in.seekg(pos, std::ios::beg);
in.clear();
in.seekg(pos, std::ios::beg);
c = in.peek();
assert(! (std::isdigit(c) || c == '.'));
parse_ident(in);
} else {
throw;
}
c = in.peek();
assert(! (std::isdigit(c) || c == '.'));
parse_ident(in);
} else {
kind = VALUE;
value = temp;
}
}
break;

View file

@ -16,13 +16,13 @@ class reconcile_transactions : public item_handler<transaction_t>
reconcile_transactions();
public:
reconcile_transactions(item_handler<transaction_t> * handler,
reconcile_transactions(xact_handler_ptr handler,
const value_t& _balance,
const datetime_t& _cutoff)
: item_handler<transaction_t>(handler),
balance(_balance), cutoff(_cutoff) {
TRACE_CTOR(reconcile_transactions,
"item_handler<transaction_t> *, const value_t&, const datetime_t&");
"xact_handler_ptr, const value_t&, const datetime_t&");
}
virtual ~reconcile_transactions() throw() {
TRACE_DTOR(reconcile_transactions);

266
report.cc
View file

@ -30,20 +30,272 @@
*/
#include "report.h"
#include "reconcile.h"
namespace ledger {
void report_t::apply_transforms(expr::scope_t& scope)
xact_handler_ptr
report_t::chain_xact_handlers(xact_handler_ptr base_handler,
const bool handle_individual_transactions)
{
#if 0
typedef tuple<shared_ptr<transform_t>, value_t> transform_details_tuple;
bool remember_components = false;
foreach (transform_details_tuple& transform_details, transforms) {
expr::call_scope_t call_args(scope);
call_args.set_args(transform_details.get<1>());
(*transform_details.get<0>())(call_args);
xact_handler_ptr handler(base_handler);
// format_transactions write each transaction received to the
// output stream.
if (handle_individual_transactions) {
// truncate_entries cuts off a certain number of _entries_ from
// being displayed. It does not affect calculation.
if (head_entries || tail_entries)
handler.reset(new truncate_entries(handler, head_entries, tail_entries));
// filter_transactions will only pass through transactions
// matching the `display_predicate'.
if (! display_predicate.empty())
handler.reset(new filter_transactions(handler, display_predicate));
// calc_transactions computes the running total. When this
// appears will determine, for example, whether filtered
// transactions are included or excluded from the running total.
handler.reset(new calc_transactions(handler));
// component_transactions looks for reported transaction that
// match the given `descend_expr', and then reports the
// transactions which made up the total for that reported
// transaction.
if (! descend_expr.empty()) {
std::list<std::string> descend_exprs;
std::string::size_type beg = 0;
for (std::string::size_type pos = descend_expr.find(';');
pos != std::string::npos;
beg = pos + 1, pos = descend_expr.find(';', beg))
descend_exprs.push_back(std::string(descend_expr, beg, pos - beg));
descend_exprs.push_back(std::string(descend_expr, beg));
for (std::list<std::string>::reverse_iterator i =
descend_exprs.rbegin();
i != descend_exprs.rend();
i++)
handler.reset(new component_transactions(handler, *i));
remember_components = true;
}
// reconcile_transactions will pass through only those
// transactions which can be reconciled to a given balance
// (calculated against the transactions which it receives).
if (! reconcile_balance.empty()) {
datetime_t cutoff = current_moment;
if (! reconcile_date.empty())
cutoff = parse_datetime(reconcile_date);
handler.reset(new reconcile_transactions
(handler, value_t(reconcile_balance), cutoff));
}
// filter_transactions will only pass through transactions
// matching the `secondary_predicate'.
if (! secondary_predicate.empty())
handler.reset(new filter_transactions(handler, secondary_predicate));
// sort_transactions will sort all the transactions it sees, based
// on the `sort_order' value expression.
if (! sort_string.empty()) {
if (entry_sort)
handler.reset(new sort_entries(handler, sort_string));
else
handler.reset(new sort_transactions(handler, sort_string));
}
// changed_value_transactions adds virtual transactions to the
// list to account for changes in market value of commodities,
// which otherwise would affect the running total unpredictably.
if (show_revalued)
handler.reset(new changed_value_transactions(handler, show_revalued_only));
// collapse_transactions causes entries with multiple transactions
// to appear as entries with a subtotaled transaction for each
// commodity used.
if (show_collapsed)
handler.reset(new collapse_transactions(handler));
// subtotal_transactions combines all the transactions it receives
// into one subtotal entry, which has one transaction for each
// commodity in each account.
//
// period_transactions is like subtotal_transactions, but it
// subtotals according to time periods rather than totalling
// everything.
//
// dow_transactions is like period_transactions, except that it
// reports all the transactions that fall on each subsequent day
// of the week.
if (show_subtotal)
handler.reset(new subtotal_transactions(handler, remember_components));
if (days_of_the_week)
handler.reset(new dow_transactions(handler, remember_components));
else if (by_payee)
handler.reset(new by_payee_transactions(handler, remember_components));
// interval_transactions groups transactions together based on a
// time period, such as weekly or monthly.
if (! report_period.empty()) {
handler.reset(new interval_transactions(handler, report_period,
remember_components));
handler.reset(new sort_transactions(handler, "d"));
}
}
// invert_transactions inverts the value of the transactions it
// receives.
if (show_inverted)
handler.reset(new invert_transactions(handler));
// related_transactions will pass along all transactions related
// to the transaction received. If `show_all_related' is true,
// then all the entry's transactions are passed; meaning that if
// one transaction of an entry is to be printed, all the
// transaction for that entry will be printed.
if (show_related)
handler.reset(new related_transactions(handler, show_all_related));
// This filter_transactions will only pass through transactions
// matching the `predicate'.
if (! predicate.empty())
handler.reset(new filter_transactions(handler, predicate));
#if 0
// budget_transactions takes a set of transactions from a data
// file and uses them to generate "budget transactions" which
// balance against the reported transactions.
//
// forecast_transactions is a lot like budget_transactions, except
// that it adds entries only for the future, and does not balance
// them against anything but the future balance.
if (budget_flags) {
budget_transactions * budget_handler
= new budget_transactions(handler, budget_flags);
budget_handler->add_period_entries(journal->period_entries);
handler.reset(budget_handler;
// Apply this before the budget handler, so that only matching
// transactions are calculated toward the budget. The use of
// filter_transactions above will further clean the results so
// that no automated transactions that don't match the filter get
// reported.
if (! predicate.empty())
handler.reset(new filter_transactions(handler, predicate));
}
else if (! forecast_limit.empty()) {
forecast_transactions * forecast_handler
= new forecast_transactions(handler, forecast_limit);
forecast_handler->add_period_entries(journal->period_entries);
handler.reset(forecast_handler;
// See above, under budget_transactions.
if (! predicate.empty())
handler.reset(new filter_transactions(handler, predicate));
}
#endif
if (comm_as_payee)
handler.reset(new set_comm_as_payee(handler));
else if (code_as_payee)
handler.reset(new set_code_as_payee(handler));
return handler;
}
void report_t::transactions_report(xact_handler_ptr handler)
{
session_transactions_iterator walker(session);
pass_down_transactions(chain_xact_handlers(handler), walker);
handler->flush();
if (DO_VERIFY())
clean_transactions();
}
void report_t::entry_report(xact_handler_ptr handler, entry_t& entry)
{
entry_transactions_iterator walker(entry);
pass_down_transactions(chain_xact_handlers(handler), walker);
handler->flush();
if (DO_VERIFY())
clean_transactions(entry);
}
void report_t::sum_all_accounts()
{
session_transactions_iterator walker(session);
pass_down_transactions
(chain_xact_handlers(xact_handler_ptr(new set_account_value), false),
walker);
// no flush() needed with set_account_value
sum_accounts(*session.master);
}
void report_t::accounts_report(acct_handler_ptr handler,
const bool print_final_total)
{
sum_all_accounts();
if (sort_string.empty()) {
accounts_iterator walker(*session.master);
pass_down_accounts<accounts_iterator>(handler, walker);
} else {
sorted_accounts_iterator walker(*session.master, sort_string);
pass_down_accounts<sorted_accounts_iterator>(handler, walker);
}
handler->flush();
if (print_final_total && account_has_xdata(*session.master)) {
account_xdata_t& xdata = account_xdata(*session.master);
if (! show_collapsed && xdata.total) {
#if 0
*out << "--------------------\n";
xdata.value = xdata.total;
handler->format.format(*out, details_t(*journal->master));
#endif
}
}
if (DO_VERIFY()) {
clean_transactions();
clean_accounts();
}
}
void report_t::commodities_report(const string& format)
{
}
void report_t::entry_report(const entry_t& entry, const string& format)
{
}
void report_t::clean_transactions()
{
session_transactions_iterator walker(session);
pass_down_transactions
(xact_handler_ptr(new clear_transaction_xdata), walker);
}
void report_t::clean_transactions(entry_t& entry)
{
entry_transactions_iterator walker(entry);
pass_down_transactions(xact_handler_ptr(new clear_transaction_xdata), walker);
}
void report_t::clean_accounts()
{
accounts_iterator acct_walker(*session.master);
pass_down_accounts<accounts_iterator>
(acct_handler_ptr(new clear_account_xdata), acct_walker);
}
value_t report_t::abbrev(expr::call_scope_t& args)

141
report.h
View file

@ -33,9 +33,54 @@
#define _REPORT_H
#include "session.h"
#include "walk.h"
namespace ledger {
// These are the elements of any report:
//
// 1. Formatting string used for outputting the underlying ReportedType.
//
// 2. Handler object for the ReportedType. This is constructed using #1, or
// else #1 is ignored completely. This handler object is also constructed
// with the output stream that will be used during formatting.
//
// --- The details of #1 and #2 together represent the ItemHandler.
//
// 3. Mode of the report. Currently there are four modes:
//
// a. Transaction or commodity iteration. In this mode, all the journal's
// entries, the transactions of a specific entry, or all the journal's
// commodities are walked. In the first two cases, it's the underlying
// transactions which are passed to #2; in the second case, each
// commodity is passed to #2.
//
// b. Account iteration. This employs step 'a', but add a prologue and
// epilogue to it. In the prologue it "sums" all account totals and
// subtotals; in the epilogue it calls yet another handler whose job is
// reporting (the handler used in 'a' is only for calculation).
//
// There is one variation on 'b' in which a "totals" line is also
// displayed.
//
// c. Write journal. In this mode, a single function is called that output
// the journal object as a textual file. #2 is used to print out each
// transaction in the journal.
//
// d. Dump binary file. This is just like 'c', except that it dumps out a
// binary file and #2 is completely ignored.
//
// 4. For 'a' and 'b' in #3, there is a different iteration function called,
// depending on whether we're iterating:
//
// a. The transactions of an entry: walk_transactions.
// b. The entries of a journal: walk_entries.
// c. The commodities of a journal: walk_commodities.
//
// 5. Finally, for the 'a' and 'b' reporting modes, there is a variant which
// says that the formatter should be "flushed" after the entities are
// iterated. This does not happen for the commodities iteration, however.
class report_t : public expr::symbol_scope_t
{
report_t();
@ -46,43 +91,115 @@ public:
string amount_expr;
string total_expr;
string date_output_format;
string predicate;
string secondary_predicate;
string display_predicate;
string report_period;
string report_period_sort;
string sort_string;
string descend_expr;
string forecast_limit;
string reconcile_balance;
string reconcile_date;
unsigned long budget_flags;
int head_entries;
int tail_entries;
bool show_collapsed;
bool show_subtotal;
bool show_totals;
bool show_related;
bool show_all_related;
bool show_inverted;
bool show_empty;
bool days_of_the_week;
bool by_payee;
bool comm_as_payee;
bool code_as_payee;
bool show_revalued;
bool show_revalued_only;
bool keep_price;
bool keep_date;
bool keep_tag;
bool entry_sort;
bool sort_all;
string account;
optional<path> pager;
bool show_totals;
bool raw_mode;
session_t& session;
#if 0
transform_t * last_transform;
std::list<tuple<shared_ptr<transform_t>, value_t> > transforms;
#endif
explicit report_t(session_t& _session)
: expr::symbol_scope_t(downcast<expr::scope_t>(_session)),
head_entries(0),
tail_entries(0),
show_collapsed(false),
show_subtotal(false),
show_totals(false),
show_related(false),
show_all_related(false),
show_inverted(false),
show_empty(false),
days_of_the_week(false),
by_payee(false),
comm_as_payee(false),
code_as_payee(false),
show_revalued(false),
show_revalued_only(false),
keep_price(false),
keep_date(false),
keep_tag(false),
entry_sort(false),
sort_all(false),
raw_mode(false),
session(_session)
#if 0
,
last_transform(NULL)
#endif
{
TRACE_CTOR(report_t, "session_t&");
#if 0
eval("t=total,TOT=0,T()=(TOT=TOT+t,TOT)");
#endif
value_expr::amount_expr.reset(new value_expr("@a"));
value_expr::total_expr.reset(new value_expr("@O"));
}
virtual ~report_t() throw() {
virtual ~report_t() {
TRACE_DTOR(report_t);
}
void apply_transforms(expr::scope_t& scope);
//
// Actual report generation; this is why we're here...
//
xact_handler_ptr
chain_xact_handlers(xact_handler_ptr handler,
const bool handle_individual_transactions = true);
void transactions_report(xact_handler_ptr handler);
void entry_report(xact_handler_ptr handler, entry_t& entry);
void sum_all_accounts();
void accounts_report(acct_handler_ptr handler,
const bool print_final_total = true);
void commodities_report(const string& format);
void entry_report(const entry_t& entry, const string& format);
void clean_transactions();
void clean_transactions(entry_t& entry);
void clean_accounts();
//
// Utility functions for value expressions

View file

@ -73,22 +73,17 @@ session_t::session_t()
: symbol_scope_t(),
register_format
("%((//entry)%{date} %-.20{payee}"
"%((./xact)%32|%-22{abbrev(account, 22)} %12.67t %12.80T\n))"),
("%D %-.20P %-.22A %12.67t %!12.80T\n%/"
"%32|%-.22A %12.67t %!12.80T\n"),
wide_register_format
("%D %-.35P %-.38A %22.108t %!22.132T\n%/"
"%48|%-.38A %22.108t %!22.132T\n"),
print_format
#if 1
("%(/%(/%{date} %-.20{payee}\n%(: %-34{account} %12t\n)\n))"),
#else
("\n%d %Y%C%P\n %-34W %12o%n\n%/ %-34W %12o%n\n"),
#endif
balance_format
("%(/%(//%20t %{\" \" * rdepth}%{rname}\n))--------------------\n%20t\n"),
("%20T %2_%-a\n"),
equity_format
("%((/)%{ftime(now, date_format)} %-.20{\"Opening Balance\"}\n%((.//account[value != 0]) %-34{fullname} %12{value}\n)\n)"),
("\n%D %Y%C%P\n%/ %-34W %12t\n"),
plot_amount_format
("%D %(@S(@t))\n"),
plot_total_format
@ -116,7 +111,9 @@ session_t::session_t()
abbrev_length(2),
ansi_codes(false),
ansi_invert(false)
ansi_invert(false),
master(new account_t(NULL, ""))
{
TRACE_CTOR(session_t, "");
}
@ -223,6 +220,27 @@ std::size_t session_t::read_data(journal_t& journal,
return entry_count;
}
namespace {
account_t * find_account_re_(account_t * account, const mask_t& regexp)
{
if (regexp.match(account->fullname()))
return account;
for (accounts_map::iterator i = account->accounts.begin();
i != account->accounts.end();
i++)
if (account_t * a = find_account_re_((*i).second, regexp))
return a;
return NULL;
}
}
account_t * session_t::find_account_re(const string& regexp)
{
return find_account_re_(master, mask_t(regexp));
}
#if 0
value_t session_t::resolve(const string& name, expr::scope_t& locals)
{

View file

@ -79,9 +79,16 @@ class session_t : public expr::symbol_scope_t
ptr_list<journal_t> journals;
ptr_list<parser_t> parsers;
account_t * master;
mutable accounts_map accounts_cache;
session_t();
virtual ~session_t() throw() {
virtual ~session_t() {
TRACE_DTOR(session_t);
assert(master);
checked_delete(master);
}
journal_t * create_journal() {
@ -129,6 +136,28 @@ class session_t : public expr::symbol_scope_t
checked_delete(parser);
}
//
// Dealing with accounts
//
void add_account(account_t * acct) {
master->add_account(acct);
}
bool remove_account(account_t * acct) {
return master->remove_account(acct);
}
account_t * find_account(const string& name, bool auto_create = true) {
accounts_map::iterator c = accounts_cache.find(name);
if (c != accounts_cache.end())
return (*c).second;
account_t * account = master->find_account(name, auto_create);
accounts_cache.insert(accounts_map::value_type(name, account));
return account;
}
account_t * find_account_re(const string& regexp);
//
// Scope members
//

View file

@ -149,7 +149,7 @@ public:
explicit scope_t(type_t _type) : type_(_type) {
TRACE_CTOR(scope_t, "type_t");
}
virtual ~scope_t() throw() {
virtual ~scope_t() {
TRACE_DTOR(scope_t);
}
@ -193,7 +193,7 @@ public:
: scope_t(_type), parent(&_parent) {
TRACE_CTOR(child_scope_t, "scope_t&, type_t");
}
virtual ~child_scope_t() throw() {
virtual ~child_scope_t() {
TRACE_DTOR(child_scope_t);
}
public:
@ -245,7 +245,7 @@ public:
: child_scope_t(_parent, SYMBOL_SCOPE) {
TRACE_CTOR(symbol_scope_t, "scope_t&");
}
virtual ~symbol_scope_t() throw() {
virtual ~symbol_scope_t() {
TRACE_DTOR(symbol_scope_t);
}
@ -267,7 +267,7 @@ public:
: child_scope_t(_parent, CALL_SCOPE) {
TRACE_CTOR(call_scope_t, "scope_t&");
}
virtual ~call_scope_t() throw() {
virtual ~call_scope_t() {
TRACE_DTOR(call_scope_t);
}
@ -862,6 +862,9 @@ public:
reset(_expr.get());
return *this;
}
value_expr& operator=(const string& _expr) {
return *this = value_expr(_expr);
}
operator bool() const throw() {
return ptr.get() != NULL;

147
walk.cc
View file

@ -1,7 +1,7 @@
#include "walk.h"
#include "session.h"
#include "format.h"
#include "textual.h"
#include "util.h"
#include <algorithm>
@ -49,7 +49,7 @@ void add_transaction_to(const transaction_t& xact, value_t& value)
transaction_xdata_(xact).dflags & TRANSACTION_COMPOUND) {
value += transaction_xdata_(xact).value;
}
else if (xact.cost || ! value.is_realzero()) {
else if (xact.cost || (! value.is_null() && ! value.is_realzero())) {
// jww (2008-04-24): Is this costly?
value.add(xact.amount, xact.cost ? optional<amount_t>(*xact.cost) : none);
}
@ -58,6 +58,57 @@ void add_transaction_to(const transaction_t& xact, value_t& value)
}
}
void entries_iterator::reset(session_t& session)
{
journals_i = session.journals.begin();
journals_end = session.journals.end();
journals_uninitialized = false;
if (journals_i != journals_end) {
entries_i = (*journals_i).entries.begin();
entries_end = (*journals_i).entries.end();
entries_uninitialized = false;
} else {
entries_uninitialized = true;
}
}
entry_t * entries_iterator::operator()()
{
if (entries_i == entries_end) {
journals_i++;
if (journals_i == journals_end)
return NULL;
entries_i = (*journals_i).entries.begin();
entries_end = (*journals_i).entries.end();
}
return *entries_i++;
}
void session_transactions_iterator::reset(session_t& session)
{
entries.reset(session);
entry_t * entry = entries();
if (entry != NULL)
xacts.reset(*entry);
}
transaction_t * session_transactions_iterator::operator()()
{
transaction_t * xact = xacts();
if (xact == NULL) {
entry_t * entry = entries();
if (entry != NULL) {
xacts.reset(*entry);
xact = xacts();
}
}
return xact;
}
void truncate_entries::flush()
{
if (! xacts.size())
@ -846,52 +897,59 @@ void sum_accounts(account_t& account)
xdata.total_count += xdata.count;
}
void sort_accounts(account_t& account,
const value_expr& sort_order,
accounts_deque& accounts)
account_t * accounts_iterator::operator()()
{
while (! accounts_i.empty() &&
accounts_i.back() == accounts_end.back()) {
accounts_i.pop_back();
accounts_end.pop_back();
}
if (accounts_i.empty())
return NULL;
account_t * account = (*(accounts_i.back()++)).second;
assert(account);
// If this account has children, queue them up to be iterated next.
if (! account->accounts.empty())
push_back(*account);
return account;
}
void sorted_accounts_iterator::sort_accounts(account_t& account,
accounts_deque_t& deque)
{
for (accounts_map::iterator i = account.accounts.begin();
i != account.accounts.end();
i++)
accounts.push_back((*i).second);
deque.push_back((*i).second);
std::stable_sort(accounts.begin(), accounts.end(),
compare_items<account_t>(sort_order));
std::stable_sort(deque.begin(), deque.end(),
compare_items<account_t>(sort_cmp));
}
void walk_accounts(account_t& account,
item_handler<account_t>& handler,
const optional<value_expr>& sort_order)
account_t * sorted_accounts_iterator::operator()()
{
handler(account);
if (sort_order) {
accounts_deque accounts;
sort_accounts(account, *sort_order, accounts);
for (accounts_deque::const_iterator i = accounts.begin();
i != accounts.end();
i++) {
account_xdata(**i).dflags &= ~ACCOUNT_SORT_CALC;
walk_accounts(**i, handler, sort_order);
}
} else {
for (accounts_map::const_iterator i = account.accounts.begin();
i != account.accounts.end();
i++)
walk_accounts(*(*i).second, handler);
while (! sorted_accounts_i.empty() &&
sorted_accounts_i.back() == sorted_accounts_end.back()) {
sorted_accounts_i.pop_back();
sorted_accounts_end.pop_back();
assert(! accounts_list.empty());
accounts_list.pop_back();
}
}
if (sorted_accounts_i.empty())
return NULL;
void walk_accounts(account_t& account,
item_handler<account_t>& handler,
const string& sort_string)
{
if (! sort_string.empty()) {
value_expr sorter(sort_string);
walk_accounts(account, handler, optional<value_expr>(sorter));
} else {
walk_accounts(account, handler);
}
account_t * account = *sorted_accounts_i.back()++;
assert(account);
// If this account has children, queue them up to be iterated next.
if (! account->accounts.empty())
push_back(*account);
account_xdata(*account).dflags &= ~ACCOUNT_SORT_CALC;
return account;
}
void walk_commodities(commodity_pool_t::commodities_by_ident& commodities,
@ -933,4 +991,17 @@ void walk_commodities(commodity_pool_t::commodities_by_ident& commodities,
clear_entries_transactions(entry_temps);
}
void journals_iterator::reset(session_t& session)
{
journals_i = session.journals.begin();
journals_end = session.journals.end();
}
journal_t * journals_iterator::operator()()
{
if (journals_i == journals_end)
return NULL;
return &(*journals_i++);
}
} // namespace ledger

376
walk.h
View file

@ -2,41 +2,37 @@
#define _WALK_H
#include "journal.h"
#include "balance.h"
#include "valexpr.h"
#include <iostream>
#include <fstream>
#include <deque>
namespace ledger {
template <typename T>
struct item_handler : public noncopyable
{
item_handler * handler;
shared_ptr<item_handler> handler;
public:
item_handler() : handler(NULL) {
item_handler() {
TRACE_CTOR(item_handler, "");
}
item_handler(item_handler * _handler) : handler(_handler) {
TRACE_CTOR(item_handler, "item_handler *");
item_handler(shared_ptr<item_handler> _handler) : handler(_handler) {
TRACE_CTOR(item_handler, "shared_ptr<item_handler>");
}
virtual ~item_handler() {
TRACE_DTOR(item_handler);
}
virtual void flush() {
if (handler)
if (handler.get())
handler->flush();
}
virtual void operator()(T& item) {
if (handler)
(*handler)(item);
if (handler.get())
(*handler.get())(item);
}
};
typedef shared_ptr<item_handler<transaction_t> > xact_handler_ptr;
template <typename T>
class compare_items
{
@ -167,29 +163,98 @@ inline const account_t * xact_account(const transaction_t& xact) {
//////////////////////////////////////////////////////////////////////
inline void walk_transactions(transactions_list::iterator begin,
transactions_list::iterator end,
item_handler<transaction_t>& handler) {
for (transactions_list::iterator i = begin; i != end; i++)
handler(**i);
}
class entries_iterator : public noncopyable
{
ptr_list<journal_t>::iterator journals_i;
ptr_list<journal_t>::iterator journals_end;
inline void walk_transactions(transactions_list& list,
item_handler<transaction_t>& handler) {
walk_transactions(list.begin(), list.end(), handler);
}
bool journals_uninitialized;
inline void walk_entries(entries_list::iterator begin,
entries_list::iterator end,
item_handler<transaction_t>& handler) {
for (entries_list::iterator i = begin; i != end; i++)
walk_transactions((*i)->transactions, handler);
}
entries_list::iterator entries_i;
entries_list::iterator entries_end;
inline void walk_entries(entries_list& list,
item_handler<transaction_t>& handler) {
walk_entries(list.begin(), list.end(), handler);
}
bool entries_uninitialized;
public:
entries_iterator()
: journals_uninitialized(true), entries_uninitialized(true) {
TRACE_CTOR(entries_iterator, "");
}
entries_iterator(session_t& session)
: journals_uninitialized(true), entries_uninitialized(true) {
TRACE_CTOR(entries_iterator, "session_t&");
reset(session);
}
~entries_iterator() throw() {
TRACE_DTOR(entries_iterator);
}
void reset(session_t& session);
entry_t * operator()();
};
class transactions_iterator : public noncopyable
{
public:
virtual transaction_t * operator()() = 0;
};
class entry_transactions_iterator : public transactions_iterator
{
transactions_list::iterator xacts_i;
transactions_list::iterator xacts_end;
bool xacts_uninitialized;
public:
entry_transactions_iterator() : xacts_uninitialized(true) {
TRACE_CTOR(entry_transactions_iterator, "");
}
entry_transactions_iterator(entry_t& entry)
: xacts_uninitialized(true) {
TRACE_CTOR(entry_transactions_iterator, "entry_t&");
reset(entry);
}
virtual ~entry_transactions_iterator() throw() {
TRACE_DTOR(entry_transactions_iterator);
}
void reset(entry_t& entry) {
xacts_i = entry.transactions.begin();
xacts_end = entry.transactions.end();
xacts_uninitialized = false;
}
virtual transaction_t * operator()() {
if (xacts_i == xacts_end || xacts_uninitialized)
return NULL;
return *xacts_i++;
}
};
class session_transactions_iterator : public transactions_iterator
{
entries_iterator entries;
entry_transactions_iterator xacts;
public:
session_transactions_iterator() {
TRACE_CTOR(session_transactions_iterator, "");
}
session_transactions_iterator(session_t& session) {
TRACE_CTOR(session_transactions_iterator, "session_t&");
reset(session);
}
virtual ~session_transactions_iterator() throw() {
TRACE_DTOR(session_transactions_iterator);
}
void reset(session_t& session);
virtual transaction_t * operator()();
};
//////////////////////////////////////////////////////////////////////
@ -210,6 +275,25 @@ public:
}
};
class pass_down_transactions : public item_handler<transaction_t>
{
pass_down_transactions();
public:
pass_down_transactions(xact_handler_ptr handler,
transactions_iterator& iter)
: item_handler<transaction_t>(handler) {
TRACE_CTOR(pass_down_transactions,
"xact_handler_ptr, transactions_iterator");
for (transaction_t * xact = iter(); xact; xact = iter())
item_handler<transaction_t>::operator()(*xact);
}
virtual ~pass_down_transactions() {
TRACE_DTOR(pass_down_transactions);
}
};
class truncate_entries : public item_handler<transaction_t>
{
int head_count;
@ -220,11 +304,11 @@ class truncate_entries : public item_handler<transaction_t>
truncate_entries();
public:
truncate_entries(item_handler<transaction_t> * handler,
truncate_entries(xact_handler_ptr handler,
int _head_count, int _tail_count)
: item_handler<transaction_t>(handler),
head_count(_head_count), tail_count(_tail_count) {
TRACE_CTOR(truncate_entries, "item_handler<transaction_t> *, int, int");
TRACE_CTOR(truncate_entries, "xact_handler_ptr, int, int");
}
virtual ~truncate_entries() {
TRACE_DTOR(truncate_entries);
@ -239,7 +323,7 @@ public:
class set_account_value : public item_handler<transaction_t>
{
public:
set_account_value(item_handler<transaction_t> * handler = NULL)
set_account_value(xact_handler_ptr handler = xact_handler_ptr())
: item_handler<transaction_t>(handler) {}
virtual void operator()(transaction_t& xact);
@ -275,19 +359,19 @@ class sort_transactions : public item_handler<transaction_t>
sort_transactions();
public:
sort_transactions(item_handler<transaction_t> * handler,
sort_transactions(xact_handler_ptr handler,
const value_expr& _sort_order)
: item_handler<transaction_t>(handler),
sort_order(_sort_order) {
TRACE_CTOR(sort_transactions,
"item_handler<transaction_t> *, const value_expr&");
"xact_handler_ptr, const value_expr&");
}
sort_transactions(item_handler<transaction_t> * handler,
sort_transactions(xact_handler_ptr handler,
const string& _sort_order)
: item_handler<transaction_t>(handler),
sort_order(_sort_order) {
TRACE_CTOR(sort_transactions,
"item_handler<transaction_t> *, const string&");
"xact_handler_ptr, const string&");
}
virtual ~sort_transactions() {
TRACE_DTOR(sort_transactions);
@ -313,17 +397,17 @@ class sort_entries : public item_handler<transaction_t>
sort_entries();
public:
sort_entries(item_handler<transaction_t> * handler,
sort_entries(xact_handler_ptr handler,
const value_expr& _sort_order)
: sorter(handler, _sort_order) {
TRACE_CTOR(sort_entries,
"item_handler<transaction_t> *, const value_expr&");
"xact_handler_ptr, const value_expr&");
}
sort_entries(item_handler<transaction_t> * handler,
sort_entries(xact_handler_ptr handler,
const string& _sort_order)
: sorter(handler, _sort_order) {
TRACE_CTOR(sort_entries,
"item_handler<transaction_t> *, const string&");
"xact_handler_ptr, const string&");
}
virtual ~sort_entries() {
TRACE_DTOR(sort_entries);
@ -351,18 +435,18 @@ class filter_transactions : public item_handler<transaction_t>
filter_transactions();
public:
filter_transactions(item_handler<transaction_t> * handler,
filter_transactions(xact_handler_ptr handler,
const value_expr& predicate)
: item_handler<transaction_t>(handler), pred(predicate) {
TRACE_CTOR(filter_transactions,
"item_handler<transaction_t> *, const value_expr&");
"xact_handler_ptr, const value_expr&");
}
filter_transactions(item_handler<transaction_t> * handler,
filter_transactions(xact_handler_ptr handler,
const string& predicate)
: item_handler<transaction_t>(handler), pred(predicate) {
TRACE_CTOR(filter_transactions,
"item_handler<transaction_t> *, const string&");
"xact_handler_ptr, const string&");
}
virtual ~filter_transactions() {
TRACE_DTOR(filter_transactions);
@ -383,9 +467,9 @@ class calc_transactions : public item_handler<transaction_t>
calc_transactions();
public:
calc_transactions(item_handler<transaction_t> * handler)
calc_transactions(xact_handler_ptr handler)
: item_handler<transaction_t>(handler), last_xact(NULL) {
TRACE_CTOR(calc_transactions, "item_handler<transaction_t> *");
TRACE_CTOR(calc_transactions, "xact_handler_ptr");
}
virtual ~calc_transactions() {
TRACE_DTOR(calc_transactions);
@ -399,7 +483,7 @@ class invert_transactions : public item_handler<transaction_t>
invert_transactions();
public:
invert_transactions(item_handler<transaction_t> * handler)
invert_transactions(xact_handler_ptr handler)
: item_handler<transaction_t>(handler) {}
virtual void operator()(transaction_t& xact);
@ -426,11 +510,11 @@ class collapse_transactions : public item_handler<transaction_t>
collapse_transactions();
public:
collapse_transactions(item_handler<transaction_t> * handler)
collapse_transactions(xact_handler_ptr handler)
: item_handler<transaction_t>(handler), count(0),
last_entry(NULL), last_xact(NULL),
totals_account(NULL, "<Total>") {
TRACE_CTOR(collapse_transactions, "item_handler<transaction_t> *");
TRACE_CTOR(collapse_transactions, "xact_handler_ptr");
}
virtual ~collapse_transactions() {
TRACE_DTOR(collapse_transactions);
@ -455,17 +539,17 @@ class component_transactions : public item_handler<transaction_t>
component_transactions();
public:
component_transactions(item_handler<transaction_t> * handler,
component_transactions(xact_handler_ptr handler,
const value_expr& predicate)
: item_handler<transaction_t>(handler), pred(predicate) {
TRACE_CTOR(component_transactions,
"item_handler<transaction_t> *, const value_expr&");
"xact_handler_ptr, const value_expr&");
}
component_transactions(item_handler<transaction_t> * handler,
component_transactions(xact_handler_ptr handler,
const string& predicate)
: item_handler<transaction_t>(handler), pred(predicate) {
TRACE_CTOR(component_transactions,
"item_handler<transaction_t> *, const string&");
"xact_handler_ptr, const string&");
}
virtual ~component_transactions() throw() {
TRACE_DTOR(component_transactions);
@ -482,12 +566,12 @@ class related_transactions : public item_handler<transaction_t>
related_transactions();
public:
related_transactions(item_handler<transaction_t> * handler,
related_transactions(xact_handler_ptr handler,
const bool _also_matching = false)
: item_handler<transaction_t>(handler),
also_matching(_also_matching) {
TRACE_CTOR(related_transactions,
"item_handler<transaction_t> *, const bool");
"xact_handler_ptr, const bool");
}
virtual ~related_transactions() throw() {
TRACE_DTOR(related_transactions);
@ -515,12 +599,12 @@ class changed_value_transactions : public item_handler<transaction_t>
changed_value_transactions();
public:
changed_value_transactions(item_handler<transaction_t> * handler,
changed_value_transactions(xact_handler_ptr handler,
bool _changed_values_only)
: item_handler<transaction_t>(handler),
changed_values_only(_changed_values_only), last_xact(NULL) {
TRACE_CTOR(changed_value_transactions,
"item_handler<transaction_t> *, bool");
"xact_handler_ptr, bool");
}
virtual ~changed_value_transactions() {
TRACE_DTOR(changed_value_transactions);
@ -584,12 +668,12 @@ public:
datetime_t start;
datetime_t finish;
subtotal_transactions(item_handler<transaction_t> * handler,
subtotal_transactions(xact_handler_ptr handler,
bool _remember_components = false)
: item_handler<transaction_t>(handler),
remember_components(_remember_components) {
TRACE_CTOR(subtotal_transactions,
"item_handler<transaction_t> *, bool");
"xact_handler_ptr, bool");
}
virtual ~subtotal_transactions() {
TRACE_DTOR(subtotal_transactions);
@ -623,21 +707,21 @@ class interval_transactions : public subtotal_transactions
interval_transactions();
public:
interval_transactions(item_handler<transaction_t> * _handler,
interval_transactions(xact_handler_ptr _handler,
const interval_t& _interval,
bool remember_components = false)
: subtotal_transactions(_handler, remember_components),
interval(_interval), last_xact(NULL), started(false) {
TRACE_CTOR(interval_transactions,
"item_handler<transaction_t> *, const interval_t&, bool");
"xact_handler_ptr, const interval_t&, bool");
}
interval_transactions(item_handler<transaction_t> * _handler,
interval_transactions(xact_handler_ptr _handler,
const string& _interval,
bool remember_components = false)
: subtotal_transactions(_handler, remember_components),
interval(_interval), last_xact(NULL), started(false) {
TRACE_CTOR(interval_transactions,
"item_handler<transaction_t> *, const string&, bool");
"xact_handler_ptr, const string&, bool");
}
virtual ~interval_transactions() throw() {
TRACE_DTOR(interval_transactions);
@ -664,12 +748,12 @@ class by_payee_transactions : public item_handler<transaction_t>
by_payee_transactions();
public:
by_payee_transactions(item_handler<transaction_t> * handler,
by_payee_transactions(xact_handler_ptr handler,
bool _remember_components = false)
: item_handler<transaction_t>(handler),
remember_components(_remember_components) {
TRACE_CTOR(by_payee_transactions,
"item_handler<transaction_t> *, bool");
"xact_handler_ptr, bool");
}
virtual ~by_payee_transactions();
@ -685,9 +769,9 @@ class set_comm_as_payee : public item_handler<transaction_t>
set_comm_as_payee();
public:
set_comm_as_payee(item_handler<transaction_t> * handler)
set_comm_as_payee(xact_handler_ptr handler)
: item_handler<transaction_t>(handler) {
TRACE_CTOR(set_comm_as_payee, "item_handler<transaction_t> *");
TRACE_CTOR(set_comm_as_payee, "xact_handler_ptr");
}
virtual ~set_comm_as_payee() {
TRACE_DTOR(set_comm_as_payee);
@ -705,9 +789,9 @@ class set_code_as_payee : public item_handler<transaction_t>
set_code_as_payee();
public:
set_code_as_payee(item_handler<transaction_t> * handler)
set_code_as_payee(xact_handler_ptr handler)
: item_handler<transaction_t>(handler) {
TRACE_CTOR(set_code_as_payee, "item_handler<transaction_t> *");
TRACE_CTOR(set_code_as_payee, "xact_handler_ptr");
}
virtual ~set_code_as_payee() {
TRACE_DTOR(set_code_as_payee);
@ -724,10 +808,10 @@ class dow_transactions : public subtotal_transactions
dow_transactions();
public:
dow_transactions(item_handler<transaction_t> * handler,
dow_transactions(xact_handler_ptr handler,
bool remember_components = false)
: subtotal_transactions(handler, remember_components) {
TRACE_CTOR(dow_transactions, "item_handler<transaction_t> *, bool");
TRACE_CTOR(dow_transactions, "xact_handler_ptr, bool");
}
virtual ~dow_transactions() throw() {
TRACE_DTOR(dow_transactions);
@ -752,9 +836,9 @@ protected:
std::list<transaction_t> xact_temps;
public:
generate_transactions(item_handler<transaction_t> * handler)
generate_transactions(xact_handler_ptr handler)
: item_handler<transaction_t>(handler) {
TRACE_CTOR(dow_transactions, "item_handler<transaction_t> *");
TRACE_CTOR(dow_transactions, "xact_handler_ptr");
}
virtual ~generate_transactions() {
@ -778,11 +862,11 @@ class budget_transactions : public generate_transactions
budget_transactions();
public:
budget_transactions(item_handler<transaction_t> * handler,
budget_transactions(xact_handler_ptr handler,
unsigned long _flags = BUDGET_BUDGETED)
: generate_transactions(handler), flags(_flags) {
TRACE_CTOR(budget_transactions,
"item_handler<transaction_t> *, unsigned long");
"xact_handler_ptr, unsigned long");
}
virtual ~budget_transactions() throw() {
TRACE_DTOR(budget_transactions);
@ -798,17 +882,15 @@ class forecast_transactions : public generate_transactions
item_predicate<transaction_t> pred;
public:
forecast_transactions(item_handler<transaction_t> * handler,
forecast_transactions(xact_handler_ptr handler,
const value_expr& predicate)
: generate_transactions(handler), pred(predicate) {
TRACE_CTOR(forecast_transactions,
"item_handler<transaction_t> *, const value_expr&");
TRACE_CTOR(forecast_transactions, "xact_handler_ptr, const value_expr&");
}
forecast_transactions(item_handler<transaction_t> * handler,
forecast_transactions(xact_handler_ptr handler,
const string& predicate)
: generate_transactions(handler), pred(predicate) {
TRACE_CTOR(forecast_transactions,
"item_handler<transaction_t> *, const string&");
TRACE_CTOR(forecast_transactions, "xact_handler_ptr, const string&");
}
virtual ~forecast_transactions() throw() {
TRACE_DTOR(forecast_transactions);
@ -859,8 +941,76 @@ inline account_xdata_t& account_xdata_(const account_t& account) {
account_xdata_t& account_xdata(const account_t& account);
void sum_accounts(account_t& account);
//////////////////////////////////////////////////////////////////////
class accounts_iterator : public noncopyable
{
std::list<accounts_map::const_iterator> accounts_i;
std::list<accounts_map::const_iterator> accounts_end;
public:
accounts_iterator() {
TRACE_CTOR(accounts_iterator, "");
}
accounts_iterator(account_t& account) {
TRACE_CTOR(accounts_iterator, "account_t&");
push_back(account);
}
virtual ~accounts_iterator() throw() {
TRACE_DTOR(accounts_iterator);
}
void push_back(account_t& account) {
accounts_i.push_back(account.accounts.begin());
accounts_end.push_back(account.accounts.end());
}
virtual account_t * operator()();
};
class sorted_accounts_iterator : public noncopyable
{
value_expr sort_cmp;
typedef std::deque<account_t *> accounts_deque_t;
std::list<accounts_deque_t> accounts_list;
std::list<accounts_deque_t::const_iterator> sorted_accounts_i;
std::list<accounts_deque_t::const_iterator> sorted_accounts_end;
public:
sorted_accounts_iterator(const string& sort_order) {
TRACE_CTOR(sorted_accounts_iterator, "const string&");
sort_cmp = value_expr(sort_order);
}
sorted_accounts_iterator(account_t& account, const string& sort_order) {
TRACE_CTOR(sorted_accounts_iterator, "account_t&, const string&");
sort_cmp = value_expr(sort_order);
push_back(account);
}
virtual ~sorted_accounts_iterator() throw() {
TRACE_DTOR(sorted_accounts_iterator);
}
void sort_accounts(account_t& account, accounts_deque_t& deque);
void push_back(account_t& account) {
accounts_list.push_back(accounts_deque_t());
sort_accounts(account, accounts_list.back());
sorted_accounts_i.push_back(accounts_list.back().begin());
sorted_accounts_end.push_back(accounts_list.back().end());
}
virtual account_t * operator()();
};
//////////////////////////////////////////////////////////////////////
typedef shared_ptr<item_handler<account_t> > acct_handler_ptr;
class clear_account_xdata : public item_handler<account_t>
{
public:
@ -872,25 +1022,28 @@ public:
}
};
void sum_accounts(account_t& account);
template <typename Iterator>
class pass_down_accounts : public item_handler<account_t>
{
pass_down_accounts();
typedef std::deque<account_t *> accounts_deque;
public:
pass_down_accounts(acct_handler_ptr handler, Iterator& iter)
: item_handler<account_t>(handler) {
TRACE_CTOR(pass_down_accounts,
"acct_handler_ptr, accounts_iterator");
for (account_t * account = iter(); account; account = iter())
item_handler<account_t>::operator()(*account);
}
void sort_accounts(account_t& account,
const value_expr& sort_order,
accounts_deque& accounts);
void walk_accounts(account_t& account,
item_handler<account_t>& handler,
const optional<value_expr>& sort_order = none);
void walk_accounts(account_t& account,
item_handler<account_t>& handler,
const string& sort_string);
virtual ~pass_down_accounts() {
TRACE_DTOR(pass_down_accounts);
}
};
//////////////////////////////////////////////////////////////////////
void walk_commodities(commodity_pool_t::commodities_by_ident& commodities,
item_handler<transaction_t>& handler);
#if 0
inline void clear_journal_xdata(journal_t& journal) {
clear_transaction_xdata xact_cleaner;
walk_entries(journal.entries, xact_cleaner);
@ -898,6 +1051,31 @@ inline void clear_journal_xdata(journal_t& journal) {
clear_account_xdata acct_cleaner;
walk_accounts(*journal.master, acct_cleaner);
}
#endif
//////////////////////////////////////////////////////////////////////
class journals_iterator : public noncopyable
{
ptr_list<journal_t>::iterator journals_i;
ptr_list<journal_t>::iterator journals_end;
public:
journals_iterator() {
TRACE_CTOR(journals_iterator, "");
}
journals_iterator(session_t& session) {
TRACE_CTOR(journals_iterator, "session_t&");
reset(session);
}
virtual ~journals_iterator() throw() {
TRACE_DTOR(journals_iterator);
}
void reset(session_t& session);
virtual journal_t * operator()();
};
} // namespace ledger