summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Wiegley <johnw@newartisans.com>2009-03-03 17:08:11 -0400
committerJohn Wiegley <johnw@newartisans.com>2009-03-03 17:08:11 -0400
commiteb45a0a4f46577c6615695256e5f6866a27ef20e (patch)
tree7839ad1f692df20276921ec182a78a14b13c61b9
parentcf2548c29cbd10c41bd23d119394489e1ced8e2a (diff)
downloadfork-ledger-eb45a0a4f46577c6615695256e5f6866a27ef20e.tar.gz
fork-ledger-eb45a0a4f46577c6615695256e5f6866a27ef20e.tar.bz2
fork-ledger-eb45a0a4f46577c6615695256e5f6866a27ef20e.zip
Normalized how account totals are calculated
-rw-r--r--doc/ledger.11
-rw-r--r--src/account.cc48
-rw-r--r--src/account.h3
-rw-r--r--src/chain.cc10
-rw-r--r--src/filters.cc46
-rw-r--r--src/filters.h26
-rw-r--r--src/global.cc3
-rw-r--r--src/output.cc20
-rw-r--r--src/report.cc22
-rw-r--r--src/report.h19
10 files changed, 69 insertions, 129 deletions
diff --git a/doc/ledger.1 b/doc/ledger.1
index 551db01a..a1e84302 100644
--- a/doc/ledger.1
+++ b/doc/ledger.1
@@ -214,6 +214,7 @@ appeared in the original journal file.
.It Fl \-total Ar EXPR
.It Fl \-total-data Pq Fl J
.It Fl \-total-width Ar INT
+.It Fl \-totals
.It Fl \-trace Ar INT
.It Fl \-truncate
.It Fl \-unbudgeted
diff --git a/src/account.cc b/src/account.cc
index 9bc96564..3e39045f 100644
--- a/src/account.cc
+++ b/src/account.cc
@@ -167,26 +167,29 @@ namespace {
}
value_t get_total(account_t& account) {
- assert(account.xdata_);
- if (account.xdata_->total.is_null())
+ if (! account.xdata_ || account.xdata_->total.is_null())
return 0L;
else
return account.xdata_->total;
}
value_t get_count(account_t& account) {
- assert(account.xdata_);
- return long(account.xdata_->total_count);
+ if (account.xdata_)
+ return long(account.xdata_->total_count);
+ else
+ return 0L;
}
value_t get_subcount(account_t& account) {
- assert(account.xdata_);
- return long(account.xdata_->count);
+ if (account.xdata_)
+ return long(account.xdata_->count);
+ else
+ return 0L;
}
value_t get_amount(account_t& account) {
- assert(account.xdata_);
- if (account.xdata_->value.is_null())
+ if (! account.xdata_ ||
+ account.xdata_->value.is_null())
return 0L;
else
return account.xdata_->value;
@@ -314,33 +317,4 @@ std::size_t account_t::children_with_flags(xdata_t::flags_t flags) const
return count;
}
-void account_t::calculate_sums(expr_t& amount_expr)
-{
- xdata_t& xd(xdata());
-
- foreach (accounts_map::value_type& pair, accounts) {
- (*pair.second).calculate_sums(amount_expr);
-
- xdata_t& child_xd((*pair.second).xdata());
- if (! child_xd.total.is_null()) {
- add_or_set_value(xd.total, child_xd.total);
- xd.total_count += child_xd.total_count;
- } else {
- assert(child_xd.total_count == 0);
- assert(child_xd.count == 0);
- }
- }
-
- bind_scope_t bound_scope(*amount_expr.get_context(), *this);
- value_t amount(amount_expr.calc(bound_scope));
-
- if (! amount.is_null()) {
- DEBUG("account.sums", "Added " << amount << " to " << fullname());
- add_or_set_value(xd.total, amount);
- xd.total_count += xd.count;
- } else {
- assert(xd.count == 0);
- }
-}
-
} // namespace ledger
diff --git a/src/account.h b/src/account.h
index 3bd0b9ca..79c989bc 100644
--- a/src/account.h
+++ b/src/account.h
@@ -133,6 +133,7 @@ class account_t : public scope_t
std::size_t count; // posts counted toward amount
std::size_t total_count; // posts counted toward total
std::size_t virtuals;
+ std::size_t total_virtuals;
std::list<sort_value_t> sort_values;
@@ -183,8 +184,6 @@ class account_t : public scope_t
return xdata_ && xdata_->has_flags(flags);
}
std::size_t children_with_flags(xdata_t::flags_t flags) const;
-
- void calculate_sums(expr_t& amount_expr);
};
std::ostream& operator<<(std::ostream& out, const account_t& account);
diff --git a/src/chain.cc b/src/chain.cc
index 9155d4fa..5b1ba18c 100644
--- a/src/chain.cc
+++ b/src/chain.cc
@@ -86,13 +86,13 @@ post_handler_ptr chain_post_handlers(report_t& report,
report.HANDLER(display_total_).expr,
report.HANDLER(display_total_).expr,
report, report.HANDLED(revalued_only)));
-
- // calc_posts computes the running total. When this appears will
- // determine, for example, whether filtered posts are included or excluded
- // from the running total.
- handler.reset(new calc_posts(handler, expr));
}
+ // calc_posts computes the running total. When this appears will determine,
+ // for example, whether filtered posts are included or excluded from the
+ // running total.
+ handler.reset(new calc_posts(handler, expr, report.HANDLED(totals)));
+
// unround_posts will unround the amounts in all postings
if (report.HANDLED(unround))
handler.reset(new unround_posts(handler));
diff --git a/src/filters.cc b/src/filters.cc
index ea3ed99d..bdcd1b67 100644
--- a/src/filters.cc
+++ b/src/filters.cc
@@ -118,26 +118,6 @@ void truncate_xacts::operator()(post_t& post)
posts.push_back(&post);
}
-void set_account_value::operator()(post_t& post)
-{
- account_t * acct = post.reported_account();
-
- account_t::xdata_t& xdata(acct->xdata());
- DEBUG("account.sums", "Account value was = " << xdata.value);
- post.add_to_value(xdata.value, amount_expr);
- DEBUG("account.sums", "Account value is = " << xdata.value);
-
- xdata.count++;
- if (post.has_flags(POST_VIRTUAL))
- xdata.virtuals++;
-
- DEBUG("account.display",
- "Visiting account: " << post.account->fullname());
- post.account->xdata().add_flags(ACCOUNT_EXT_VISITED);
-
- item_handler<post_t>::operator()(post);
-}
-
void sort_posts::post_accumulated_posts()
{
std::stable_sort(posts.begin(), posts.end(),
@@ -222,6 +202,32 @@ void calc_posts::operator()(post_t& post)
post.add_to_value(xdata.total, amount_expr);
+ if (calc_totals) {
+ account_t * acct = post.reported_account();
+
+ account_t::xdata_t * acct_xdata = &acct->xdata();
+
+ post.add_to_value(acct_xdata->value, amount_expr);
+
+ acct_xdata->count++;
+ acct_xdata->virtuals++;
+ acct_xdata->add_flags(ACCOUNT_EXT_VISITED);
+
+ while (true) {
+ post.add_to_value(acct_xdata->total, amount_expr);
+
+ acct_xdata->total_count++;
+ if (post.has_flags(POST_VIRTUAL))
+ acct_xdata->total_virtuals++;
+
+ acct = acct->parent;
+ if (acct)
+ acct_xdata = &acct->xdata();
+ else
+ break;
+ }
+ }
+
item_handler<post_t>::operator()(post);
last_post = &post;
diff --git a/src/filters.h b/src/filters.h
index 64b688ec..aafdf082 100644
--- a/src/filters.h
+++ b/src/filters.h
@@ -185,22 +185,6 @@ public:
*
* Long.
*/
-class set_account_value : public item_handler<post_t>
-{
- expr_t& amount_expr;
-
-public:
- set_account_value(expr_t& _amount_expr)
- : item_handler<post_t>(), amount_expr(_amount_expr) {}
-
- virtual void operator()(post_t& post);
-};
-
-/**
- * @brief Brief
- *
- * Long.
- */
class sort_posts : public item_handler<post_t>
{
typedef std::deque<post_t *> posts_deque;
@@ -359,15 +343,17 @@ class calc_posts : public item_handler<post_t>
{
post_t * last_post;
expr_t& amount_expr;
+ bool calc_totals;
calc_posts();
public:
calc_posts(post_handler_ptr handler,
- expr_t& _amount_expr)
- : item_handler<post_t>(handler),
- last_post(NULL), amount_expr(_amount_expr) {
- TRACE_CTOR(calc_posts, "post_handler_ptr, expr_t&");
+ expr_t& _amount_expr,
+ bool _calc_totals = false)
+ : item_handler<post_t>(handler), last_post(NULL),
+ amount_expr(_amount_expr), calc_totals(_calc_totals) {
+ TRACE_CTOR(calc_posts, "post_handler_ptr, expr_t&, bool");
}
virtual ~calc_posts() {
TRACE_DTOR(calc_posts);
diff --git a/src/global.cc b/src/global.cc
index 22bd5b7b..dc21012c 100644
--- a/src/global.cc
+++ b/src/global.cc
@@ -408,6 +408,9 @@ void global_scope_t::normalize_report_options(const string& verb)
if (verb[0] != 'b' && verb[0] != 'r')
rep.HANDLER(base).on_only();
+ if (verb[0] == 'b' || verb == "equity")
+ rep.HANDLER(totals).on_only();
+
if (rep.HANDLED(period_) && ! rep.HANDLED(sort_all_))
rep.HANDLER(sort_xacts_).on_only();
diff --git a/src/output.cc b/src/output.cc
index f7f18351..e14c75dc 100644
--- a/src/output.cc
+++ b/src/output.cc
@@ -287,14 +287,15 @@ void format_accounts::flush()
}
}
- assert(report.session.master->has_xdata());
- account_t::xdata_t& xdata(report.session.master->xdata());
-
- if (! report.HANDLED(no_total) && top_displayed > 1 && xdata.total) {
- xdata.value = xdata.total;
- bind_scope_t bound_scope(report, *report.session.master);
- separator_format.format(out, bound_scope);
- total_line_format.format(out, bound_scope);
+ if (report.session.master->has_xdata()) {
+ account_t::xdata_t& xdata(report.session.master->xdata());
+
+ if (! report.HANDLED(no_total) && top_displayed > 1 && xdata.total) {
+ xdata.value = xdata.total;
+ bind_scope_t bound_scope(report, *report.session.master);
+ separator_format.format(out, bound_scope);
+ total_line_format.format(out, bound_scope);
+ }
}
out.flush();
@@ -306,8 +307,7 @@ void format_accounts::operator()(account_t& account)
"Proposing to format account: " << account.fullname());
if (account.has_flags(ACCOUNT_EXT_VISITED)) {
- DEBUG("account.display",
- " Account or its children visited by sum_all_accounts");
+ DEBUG("account.display", " Account or its children was visited");
bind_scope_t bound_scope(report, account);
if (disp_pred(bound_scope)) {
diff --git a/src/report.cc b/src/report.cc
index 2c145dc7..160cb698 100644
--- a/src/report.cc
+++ b/src/report.cc
@@ -67,27 +67,13 @@ void report_t::xact_report(post_handler_ptr handler, xact_t& xact)
session.clean_posts(xact);
}
-void report_t::sum_all_accounts()
-{
- expr_t& amount_expr(HANDLER(amount_).expr);
- amount_expr.set_context(this);
-
- journal_posts_iterator walker(*session.journal.get());
- pass_down_posts(chain_post_handlers
- (*this, post_handler_ptr(new set_account_value(amount_expr)),
- true), walker);
-
- expr_t& account_amount_expr(HANDLER(account_amount_).expr);
- account_amount_expr.set_context(this);
- session.master->calculate_sums(account_amount_expr);
-}
-
void report_t::accounts_report(acct_handler_ptr handler)
{
- sum_all_accounts();
+ journal_posts_iterator walker(*session.journal.get());
+ pass_down_posts(chain_post_handlers(*this, post_handler_ptr(new ignore_posts),
+ true), walker);
scoped_ptr<accounts_iterator> iter;
-
if (! HANDLED(sort_))
iter.reset(new basic_accounts_iterator(*session.master));
else
@@ -477,7 +463,6 @@ option_t<report_t> * report_t::lookup_option(const char * p)
case 'a':
OPT(abbrev_len_);
else OPT(account_);
- else OPT(account_amount_);
else OPT(actual);
else OPT(add_budget);
else OPT(amount_);
@@ -613,6 +598,7 @@ option_t<report_t> * report_t::lookup_option(const char * p)
OPT_CH(amount_);
else OPT(tail_);
else OPT(total_);
+ else OPT(totals);
else OPT(total_data);
else OPT(truncate_);
else OPT(total_width_);
diff --git a/src/report.h b/src/report.h
index 7bca98b8..f83f1745 100644
--- a/src/report.h
+++ b/src/report.h
@@ -127,8 +127,6 @@ public:
void accounts_report(acct_handler_ptr handler);
void commodities_report(post_handler_ptr handler);
- void sum_all_accounts();
-
value_t fn_amount_expr(call_scope_t& scope);
value_t fn_total_expr(call_scope_t& scope);
value_t fn_display_amount(call_scope_t& scope);
@@ -190,20 +188,6 @@ public:
CTOR(report_t, abbrev_len_) { on_with(2L); });
OPTION(report_t, account_);
- OPTION__
- (report_t, account_amount_,
- expr_t expr;
- CTOR(report_t, account_amount_) {
- set_expr("amount");
- }
- void set_expr(const string& str) {
- expr = str;
- on(str);
- }
- DO_(args) {
- set_expr(args[0].to_string());
- });
-
OPTION_(report_t, actual, DO() { // -L
parent->HANDLER(limit_).on("actual");
});
@@ -399,7 +383,6 @@ public:
OPTION_(report_t, gain, DO() { // -G
parent->HANDLER(revalued).on_only();
- parent->HANDLER(account_amount_).set_expr("amount | (0, 0)");
parent->HANDLER(amount_).set_expr("(amount, cost)");
// Since we are displaying the amounts of revalued postings, they
// will end up being composite totals, and hence a pair of pairs.
@@ -629,6 +612,8 @@ public:
set_expr(args[0].to_string());
});
+ OPTION(report_t, totals);
+
OPTION_(report_t, total_data, DO() { // -J
parent->HANDLER(format_).on_with(parent->HANDLER(plot_total_format_).value);
});