summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--amount.cc12
-rw-r--r--amount.h12
-rw-r--r--binary.cc2
-rw-r--r--derive.cc68
-rw-r--r--derive.h4
-rw-r--r--format.cc4
-rw-r--r--format.h16
-rw-r--r--journal.cc60
-rw-r--r--journal.h38
-rw-r--r--main.cc229
-rw-r--r--parsexp.cc38
-rw-r--r--reconcile.h4
-rw-r--r--report.cc264
-rw-r--r--report.h141
-rw-r--r--session.cc38
-rw-r--r--session.h31
-rw-r--r--valexpr.h11
-rw-r--r--walk.cc147
-rw-r--r--walk.h376
19 files changed, 1054 insertions, 441 deletions
diff --git a/amount.cc b/amount.cc
index 236fa461..fbad3e0c 100644
--- a/amount.cc
+++ b/amount.cc
@@ -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,
diff --git a/amount.h b/amount.h
index 648965c7..4e62dfc0 100644
--- a/amount.h
+++ b/amount.h
@@ -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,
diff --git a/binary.cc b/binary.cc
index c1c2321e..bb9ac7b4 100644
--- a/binary.cc
+++ b/binary.cc
@@ -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)
diff --git a/derive.cc b/derive.cc
index 35f89788..181dcc86 100644
--- a/derive.cc
+++ b/derive.cc
@@ -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();
diff --git a/derive.h b/derive.h
index 0df7f231..24604d1d 100644
--- a/derive.h
+++ b/derive.h
@@ -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);
diff --git a/format.cc b/format.cc
index b72a4739..bfcb81ba 100644
--- a/format.cc
+++ b/format.cc
@@ -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) {
diff --git a/format.h b/format.h
index bf2ae31e..ad18decb 100644
--- a/format.h
+++ b/format.h
@@ -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);
diff --git a/journal.cc b/journal.cc
index 23cb33cb..0ff91b7a 100644
--- a/journal.cc
+++ b/journal.cc
@@ -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;
diff --git a/journal.h b/journal.h
index b6f7108d..09be5b93 100644
--- a/journal.h
+++ b/journal.h
@@ -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);
diff --git a/main.cc b/main.cc
index a776448e..6646d5b8 100644
--- a/main.cc
+++ b/main.cc
@@ -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,44 +103,58 @@ 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
+ // Configure the output stream
- string verb = *arg++;
+#ifdef HAVE_UNIX_PIPES
+ int status, pfd[2]; // Pipe file descriptors
+#endif
+ std::ostream * out = &std::cout;
- expr::function_t command;
+ if (report.output_file) {
+ out = new ofstream(*report.output_file);
+ }
+#ifdef HAVE_UNIX_PIPES
+ else if (report.pager) {
+ status = pipe(pfd);
+ if (status == -1)
+ throw_(std::logic_error, "Failed to create pipe");
- 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);
- ;
+ status = fork();
+ if (status < 0) {
+ throw_(std::logic_error, "Failed to fork child process");
+ }
+ else if (status == 0) { // child
+ // Duplicate pipe's reading end into stdin
+ status = dup2(pfd[0], STDIN_FILENO);
+ if (status == -1)
+ perror("dup2");
+
+ // Close unuseful file descriptors: the pipe's writing and
+ // reading ends (the latter is not needed anymore, after the
+ // duplication).
+ close(pfd[1]);
+ close(pfd[0]);
+
+ // Find command name: its the substring starting right of the
+ // rightmost '/' character in the pager pathname. See manpage
+ // for strrchr.
+ execlp(report.pager->native_file_string().c_str(),
+ basename(*report.pager).c_str(), (char *)0);
+ perror("execl");
+ exit(1);
+ }
+ else { // parent
+ close(pfd[0]);
+ out = new boost::fdostream(pfd[1]);
+ }
+ }
#endif
- else if (verb == "expr")
- ;
- else if (verb == "xpath")
- ;
- else if (verb == "parse") {
+
+ // Read the command word and create a command object based on it
+
+ string verb = *arg++;
+
+ if (verb == "parse") {
value_expr expr(*arg);
#if 0
@@ -184,17 +187,6 @@ static int read_and_report(ledger::report_t& report, int argc, char * argv[],
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.
@@ -221,55 +213,6 @@ static int read_and_report(ledger::report_t& report, int argc, char * argv[],
TRACE_FINISH(entries, 1);
TRACE_FINISH(parsing_total, 1);
- // Configure the output stream
-
-#ifdef HAVE_UNIX_PIPES
- int status, pfd[2]; // Pipe file descriptors
-#endif
- std::ostream * out = &std::cout;
-
- if (report.output_file) {
- out = new ofstream(*report.output_file);
- }
-#ifdef HAVE_UNIX_PIPES
- else if (report.pager) {
- status = pipe(pfd);
- if (status == -1)
- throw_(std::logic_error, "Failed to create pipe");
-
- status = fork();
- if (status < 0) {
- throw_(std::logic_error, "Failed to fork child process");
- }
- else if (status == 0) { // child
- // Duplicate pipe's reading end into stdin
- status = dup2(pfd[0], STDIN_FILENO);
- if (status == -1)
- perror("dup2");
-
- // Close unuseful file descriptors: the pipe's writing and
- // reading ends (the latter is not needed anymore, after the
- // duplication).
- close(pfd[1]);
- close(pfd[0]);
-
- // Find command name: its the substring starting right of the
- // rightmost '/' character in the pager pathname. See manpage
- // for strrchr.
- execlp(report.pager->native_file_string().c_str(),
- basename(*report.pager).c_str(), (char *)0);
- perror("execl");
- exit(1);
- }
- else { // parent
- close(pfd[0]);
- out = new boost::fdostream(pfd[1]);
- }
- }
-#endif
-
- report.define("ostream", value_t(out));
-
// Are we handling the expr commands? Do so now.
if (verb == "expr") {
@@ -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
diff --git a/parsexp.cc b/parsexp.cc
index b410965c..c20cfb10 100644
--- a/parsexp.cc
+++ b/parsexp.cc
@@ -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();
-
- 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;
+ pos = (long)in.tellg();
- temp.parse(in, parse_flags);
+ 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;
- 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;
diff --git a/reconcile.h b/reconcile.h
index 31bec511..9f672d6b 100644
--- a/reconcile.h
+++ b/reconcile.h
@@ -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);
diff --git a/report.cc b/report.cc
index 58947816..f86acdf0 100644
--- a/report.cc
+++ b/report.cc
@@ -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)
{
+ bool remember_components = false;
+
+ 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
- typedef tuple<shared_ptr<transform_t>, value_t> transform_details_tuple;
+ // 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;
- 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);
+ // 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)
diff --git a/report.h b/report.h
index 7f3ada88..4e65a8fc 100644
--- a/report.h
+++ b/report.h
@@ -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
diff --git a/session.cc b/session.cc
index 27c63da6..140589dc 100644
--- a/session.cc
+++ b/session.cc
@@ -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)
{
diff --git a/session.h b/session.h
index bfaeb299..edfa8d9c 100644
--- a/session.h
+++ b/session.h
@@ -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() {
@@ -130,6 +137,28 @@ class session_t : public expr::symbol_scope_t
}
//
+ // 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
//
diff --git a/valexpr.h b/valexpr.h
index 6ff74186..13db2450 100644
--- a/valexpr.h
+++ b/valexpr.h
@@ -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;
diff --git a/walk.cc b/walk.cc
index 160cde35..dcb8f2af 100644
--- a/walk.cc
+++ b/walk.cc
@@ -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()()
{
- for (accounts_map::iterator i = account.accounts.begin();
- i != account.accounts.end();
- i++)
- accounts.push_back((*i).second);
+ 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);
- std::stable_sort(accounts.begin(), accounts.end(),
- compare_items<account_t>(sort_order));
+ // If this account has children, queue them up to be iterated next.
+ if (! account->accounts.empty())
+ push_back(*account);
+
+ return account;
}
-void walk_accounts(account_t& account,
- item_handler<account_t>& handler,
- const optional<value_expr>& sort_order)
+void sorted_accounts_iterator::sort_accounts(account_t& account,
+ accounts_deque_t& deque)
{
- handler(account);
+ for (accounts_map::iterator i = account.accounts.begin();
+ i != account.accounts.end();
+ i++)
+ deque.push_back((*i).second);
- 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);
- }
+ 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 string& sort_string)
+account_t * sorted_accounts_iterator::operator()()
{
- if (! sort_string.empty()) {
- value_expr sorter(sort_string);
- walk_accounts(account, handler, optional<value_expr>(sorter));
- } else {
- walk_accounts(account, 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;
+
+ 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
diff --git a/walk.h b/walk.h
index e34926f9..66542da6 100644
--- a/walk.h
+++ b/walk.h
@@ -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