summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--amount.cc2
-rw-r--r--format.cc124
-rw-r--r--format.h58
-rw-r--r--ledger.h7
-rw-r--r--main.cc56
-rw-r--r--valexpr.h19
-rw-r--r--walk.h91
7 files changed, 231 insertions, 126 deletions
diff --git a/amount.cc b/amount.cc
index c86177b1..368a366d 100644
--- a/amount.cc
+++ b/amount.cc
@@ -220,7 +220,7 @@ amount_t& amount_t::operator=(const double value)
amount_t& amount_t::operator+=(const amount_t& amt)
{
if (amt.quantity) {
- assert(commodity == amt.commodity);
+ assert(! commodity || commodity == amt.commodity);
INIT();
mpz_add(MPZ(quantity), MPZ(quantity), MPZ(amt.quantity));
}
diff --git a/format.cc b/format.cc
index 6922c601..a509c143 100644
--- a/format.cc
+++ b/format.cc
@@ -293,30 +293,130 @@ void format_t::format_elements(std::ostream& out,
}
}
-void format_transaction::operator()(transaction_t * xact)
+void format_transaction::report_cumulative_subtotal() const
{
+ if (count == 1) {
+ if (! intercept || ! intercept(last_xact))
+ first_line_format.format_elements(output_stream, details_t(last_xact));
+ return;
+ }
+
+ assert(count > 1);
+
+ account_t splits(NULL, "<Total>");
+ transaction_t splits_total(NULL, &splits);
+ splits_total.total = subtotal;
+
+ balance_t value;
+ format_t::compute_total(value, details_t(&splits_total));
+
+ splits_total.entry = last_entry;
+ splits_total.total = last_xact->total;
+
+ bool first = true;
+ for (amounts_map::const_iterator i = value.amounts.begin();
+ i != value.amounts.end();
+ i++) {
+ splits_total.amount = (*i).second;
+ splits_total.cost = (*i).second;
+ splits_total.total += (*i).second;
+ if (first) {
+ if (! intercept || ! intercept(&splits_total))
+ first_line_format.format_elements(output_stream,
+ details_t(&splits_total));
+ first = false;
+ } else {
+ next_lines_format.format_elements(output_stream,
+ details_t(&splits_total));
+ }
+ }
+}
+
+void format_transaction::operator()(transaction_t * xact) const
+{
+ if (last_xact)
+ xact->total = last_xact->total;
+
if (inverted) {
- xact->total.quantity += - xact->amount;
- xact->total.cost += - xact->cost;
- } else {
- xact->total += *xact;
+ xact->amount.negate();
+ xact->cost.negate();
}
- xact->index = index++;
+
+ xact->total += *xact;
+ xact->index = last_xact ? last_xact->index + 1 : 0;
+
+ if (! disp_pred_functor(xact))
+ return;
+
+ xact->flags |= TRANSACTION_DISPLAYED;
// This makes the assumption that transactions from a single entry
- // will always be grouped together.
+ // are always grouped together.
+
+ if (collapsed) {
+ // If we've reached a new entry, report on the subtotal
+ // accumulated thus far.
+
+ if (last_entry && last_entry != xact->entry) {
+ report_cumulative_subtotal();
+ subtotal = 0;
+ count = 0;
+ }
+
+ subtotal += *xact;
+ count++;
+ } else {
+ if (last_entry != xact->entry) {
+ if (! intercept || ! intercept(xact))
+ first_line_format.format_elements(output_stream, details_t(xact));
+ } else {
+ next_lines_format.format_elements(output_stream, details_t(xact));
+ }
+ }
- if (last_entry != xact->entry)
- first_line_format.format_elements(output_stream, details_t(xact));
- else
- next_lines_format.format_elements(output_stream, details_t(xact));
+ if (inverted) {
+ xact->amount.negate();
+ xact->cost.negate();
+ }
last_entry = xact->entry;
+ last_xact = xact;
+}
+
+#if 0
+
+bool report_changed_values(transaction_t * xact)
+{
+ static transaction_t * last_xact = NULL;
+
+ if (last_xact) {
+ balance_t prev_bal, cur_bal;
+ format_t::compute_total(prev_bal, details_t(last_xact));
+ format_t::compute_total(cur_bal, details_t(xact));
+
+ if (balance_t diff = cur_bal - prev_bal) {
+ entry_t modified_entry;
+ transaction_t new_xact(&modified_entry, NULL);
+
+ modified_entry.date = xact ? xact->entry->date : std::time(NULL);
+ modified_entry.payee = "Commodities revalued";
+
+ new_xact.amount = diff.amount();
+ format_t::compute_value(diff, details_t(xact));
+ new_xact.total = cur_bal - diff;
+
+ functor(&new_xact);
+ }
+ }
+
+ last_xact = xact;
}
+#endif
+
void format_account::operator()(const account_t * account,
const unsigned int max_depth,
- const bool report_top)
+ const bool report_top) const
{
// Don't output the account if only one child will be displayed
// which shows the exact same amount. jww (2004-08-03): How do
diff --git a/format.h b/format.h
index 71ebdf5e..a7c49301 100644
--- a/format.h
+++ b/format.h
@@ -87,36 +87,72 @@ class format_transaction
std::ostream& output_stream;
const format_t& first_line_format;
const format_t& next_lines_format;
+ const bool collapsed;
const bool inverted;
- unsigned int index;
- entry_t * last_entry;
+
+ item_predicate<transaction_t> disp_pred_functor;
+
+ typedef bool (*intercept_t)(transaction_t * xact);
+
+ intercept_t intercept;
+
+ mutable balance_pair_t subtotal;
+ mutable unsigned int count;
+ mutable entry_t * last_entry;
+ mutable transaction_t * last_xact;
public:
format_transaction(std::ostream& _output_stream,
const format_t& _first_line_format,
const format_t& _next_lines_format,
- const bool _inverted)
+ const node_t * display_predicate,
+ const bool _collapsed = false,
+ const bool _inverted = false,
+ intercept_t _intercept = NULL)
: output_stream(_output_stream),
first_line_format(_first_line_format),
next_lines_format(_next_lines_format),
- inverted(_inverted), index(0), last_entry(NULL) {}
+ collapsed(_collapsed), inverted(_inverted),
+ disp_pred_functor(display_predicate),
+ intercept(_intercept), count(0),
+ last_entry(NULL), last_xact(NULL) {}
+
+ void start() const {}
+ void finish() const {
+ if (subtotal)
+ report_cumulative_subtotal();
+ }
- void operator()(transaction_t * xact);
+ void report_cumulative_subtotal() const;
+ void operator()(transaction_t * xact) const;
};
+// An intercept that can be used to report changes in commodity value
+bool report_changed_values(transaction_t * xact);
+
+
class format_account
{
- std::ostream& output_stream;
- const format_t& format;
- const account_t * last_account;
+ std::ostream& output_stream;
+ const format_t& format;
+
+ item_predicate<account_t> disp_pred_functor;
+
+ mutable const account_t * last_account;
public:
- format_account(std::ostream& _output_stream, const format_t& _format)
- : output_stream(_output_stream), format(_format) {}
+ format_account(std::ostream& _output_stream,
+ const format_t& _format,
+ const node_t * display_predicate = NULL)
+ : output_stream(_output_stream), format(_format),
+ disp_pred_functor(display_predicate), last_account(NULL) {}
+
+ void start() const {}
+ void finish() const {}
void operator()(const account_t * account,
const unsigned int max_depth = 1,
- const bool report_top = false);
+ const bool report_top = false) const;
};
} // namespace ledger
diff --git a/ledger.h b/ledger.h
index d309a7d6..8fec0c17 100644
--- a/ledger.h
+++ b/ledger.h
@@ -28,6 +28,8 @@ namespace ledger {
#define TRANSACTION_HANDLED 0x08
#define TRANSACTION_DISPLAYED 0x10
+#define TRANSACTION_TRANSIENT (TRANSACTION_HANDLED | TRANSACTION_DISPLAYED)
+
class entry_t;
class account_t;
@@ -44,7 +46,8 @@ class transaction_t
unsigned int index;
transaction_t(entry_t * _entry, account_t * _account)
- : entry(_entry), account(_account), flags(TRANSACTION_NORMAL) {}
+ : entry(_entry), account(_account), flags(TRANSACTION_NORMAL),
+ index(0) {}
transaction_t(entry_t * _entry,
account_t * _account,
@@ -53,7 +56,7 @@ class transaction_t
unsigned int _flags = TRANSACTION_NORMAL,
const std::string& _note = "")
: entry(_entry), account(_account), amount(_amount),
- cost(_cost), flags(_flags), note(_note) {}
+ cost(_cost), flags(_flags), note(_note), index(0) {}
};
diff --git a/main.cc b/main.cc
index 23b29cc3..cab9abed 100644
--- a/main.cc
+++ b/main.cc
@@ -31,9 +31,6 @@ static const std::string reg_fmt
static const std::string print_fmt
= "\n%10d %X%C%p\n %-34N %12o\n%/ %-34N %12o\n";
-static bool show_commodities_revalued = false;
-static bool show_commodities_revalued_only = false;
-
#if 0
static void report_value_change(std::ostream& out,
@@ -44,33 +41,6 @@ static void report_value_change(std::ostream& out,
const format_t& first_line_format,
const format_t& next_lines_format)
{
- static std::time_t prev_date = -1;
- if (prev_date == -1) {
- prev_date = date;
- return;
- }
-
- item_t temp;
- temp.date = prev_date;
- temp.total = prev_balance;
- balance_t prev_bal = format_t::compute_total(&temp);
-
- temp.date = date;
- temp.total = balance;
- balance_t cur_bal = format_t::compute_total(&temp);
-
- if (balance_t diff = cur_bal - prev_bal) {
- temp.value = diff;
- temp.total = balance;
- temp.payee = "Commodities revalued";
-
- if (value_predicate(predicate)(&temp)) {
- first_line_format.format_elements(out, &temp);
- next_lines_format.format_elements(out, &temp);
- }
- }
-
- prev_date = date;
}
void register_report(std::ostream& out,
@@ -307,6 +277,9 @@ int main(int argc, char * argv[])
bool show_inverted = false;
bool show_empty = false;
+ bool show_commodities_revalued = false;
+ bool show_commodities_revalued_only = false;
+
#ifdef DEBUG
bool debug = false;
#endif
@@ -763,16 +736,19 @@ int main(int argc, char * argv[])
if (command == "b") {
format_t format(f);
- walk_accounts(journal->master, format_account(std::cout, format),
- predicate.get(), xact_display_flags, show_subtotals,
- show_expanded ? 0 : 1, display_predicate.get(),
+ format_account formatter(std::cout, format, display_predicate.get());
+ formatter.start();
+ walk_accounts(journal->master, formatter, predicate.get(),
+ xact_display_flags, show_subtotals, show_expanded ? 0 : 1,
sort_order.get());
+ formatter.finish();
if (! display_predicate.get() ||
item_predicate<account_t>(display_predicate.get())(journal->master)) {
std::string end_format = "--------------------\n";
format.reset(end_format + f);
- format_account(std::cout, format)(journal->master, true);
+ format_account(std::cout, format)(journal->master, true,
+ display_predicate.get());
}
} else {
std::string first_line_format;
@@ -787,22 +763,26 @@ int main(int argc, char * argv[])
format_t format(first_line_format);
format_t nformat(next_lines_format);
- format_transaction formatter(std::cout, format, nformat, show_inverted);
+
+ format_transaction formatter(std::cout, format, nformat,
+ display_predicate.get(),
+ ! show_subtotals, show_inverted);
+ formatter.start();
if (! sort_order.get()) {
walk_entries(journal->entries.begin(), journal->entries.end(),
- formatter, predicate.get(), xact_display_flags,
- display_predicate.get());
+ formatter, predicate.get(), xact_display_flags);
} else {
transactions_deque transactions_pool;
walk_entries(journal->entries.begin(), journal->entries.end(),
collect_transactions(transactions_pool), predicate.get(),
- xact_display_flags, display_predicate.get());
+ xact_display_flags);
std::stable_sort(transactions_pool.begin(), transactions_pool.end(),
compare_items<transaction_t>(sort_order.get()));
walk_transactions(transactions_pool.begin(), transactions_pool.end(),
formatter);
}
+ formatter.finish();
}
// Save the cache, if need be
diff --git a/valexpr.h b/valexpr.h
index d2521998..aadbb03f 100644
--- a/valexpr.h
+++ b/valexpr.h
@@ -136,6 +136,25 @@ inline node_t * find_node(node_t * node, node_t::kind_t type) {
return result;
}
+template <typename T>
+class item_predicate
+{
+ const node_t * predicate;
+
+ public:
+ item_predicate(const node_t * _predicate) : predicate(_predicate) {}
+
+ bool operator()(const T * item) const {
+ if (predicate) {
+ balance_t result;
+ predicate->compute(result, details_t(item));
+ return result;
+ } else {
+ return true;
+ }
+ }
+};
+
} // namespace report
#endif // _REPORT_H
diff --git a/walk.h b/walk.h
index b3c39f88..850eb228 100644
--- a/walk.h
+++ b/walk.h
@@ -11,25 +11,6 @@
namespace ledger {
template <typename T>
-class item_predicate
-{
- const node_t * predicate;
-
- public:
- item_predicate(const node_t * _predicate) : predicate(_predicate) {}
-
- bool operator()(const T * item) const {
- if (predicate) {
- balance_t result;
- predicate->compute(result, details_t(item));
- return result;
- } else {
- return true;
- }
- }
-};
-
-template <typename T>
struct compare_items {
const node_t * sort_order;
@@ -59,7 +40,7 @@ class collect_transactions
collect_transactions(transactions_deque& _transactions)
: transactions(_transactions) {}
- void operator()(transaction_t * xact) {
+ void operator()(transaction_t * xact) const {
transactions.push_back(xact);
}
};
@@ -81,17 +62,14 @@ class ignore_transaction
#define OTHER_TRANSACTIONS 0x02
template <typename Function>
-void handle_transaction(transaction_t * xact, Function functor,
- item_predicate<transaction_t>& pred_functor,
- unsigned int flags)
+void handle_transaction(transaction_t * xact,
+ const Function& functor,
+ unsigned int flags)
{
if ((flags & MATCHING_TRANSACTIONS) &&
! (xact->flags & TRANSACTION_HANDLED)) {
xact->flags |= TRANSACTION_HANDLED;
- if (pred_functor(xact)) {
- xact->flags |= TRANSACTION_DISPLAYED;
- functor(xact);
- }
+ functor(xact);
}
if (flags & OTHER_TRANSACTIONS)
@@ -103,35 +81,30 @@ void handle_transaction(transaction_t * xact, Function functor,
continue;
(*i)->flags |= TRANSACTION_HANDLED;
- if (pred_functor(xact)) {
- xact->flags |= TRANSACTION_DISPLAYED;
- functor(*i);
- }
+ functor(*i);
}
}
template <typename Function>
void walk_entries(entries_list::iterator begin,
entries_list::iterator end,
- Function functor,
- const node_t * predicate,
- unsigned int flags,
- const node_t * display_predicate = NULL)
+ const Function& functor,
+ const node_t * predicate,
+ unsigned int flags)
{
item_predicate<transaction_t> pred_functor(predicate);
- item_predicate<transaction_t> disp_pred_functor(display_predicate);
for (entries_list::iterator i = begin; i != end; i++)
for (transactions_list::iterator j = (*i)->transactions.begin();
j != (*i)->transactions.end();
j++)
if (pred_functor(*j))
- handle_transaction(*j, functor, disp_pred_functor, flags);
+ handle_transaction(*j, functor, flags);
}
template <typename Function>
void walk_entries(entries_list::iterator begin,
- entries_list::iterator end, Function functor)
+ entries_list::iterator end, const Function& functor)
{
for (entries_list::iterator i = begin; i != end; i++)
for (transactions_list::iterator j = (*i)->transactions.begin();
@@ -144,7 +117,7 @@ class clear_flags
{
public:
void operator()(transaction_t * xact) const {
- xact->flags &= ~(TRANSACTION_HANDLED | TRANSACTION_DISPLAYED);
+ xact->flags &= ~TRANSACTION_TRANSIENT;
}
};
@@ -156,7 +129,8 @@ inline void clear_transaction_display_flags(entries_list::iterator begin,
template <typename Function>
void walk_transactions(transactions_list::iterator begin,
- transactions_list::iterator end, Function functor)
+ transactions_list::iterator end,
+ const Function& functor)
{
for (transactions_list::iterator i = begin; i != end; i++)
functor(*i);
@@ -164,7 +138,8 @@ void walk_transactions(transactions_list::iterator begin,
template <typename Function>
void walk_transactions(transactions_deque::iterator begin,
- transactions_deque::iterator end, Function functor)
+ transactions_deque::iterator end,
+ const Function& functor)
{
for (transactions_deque::iterator i = begin; i != end; i++)
functor(*i);
@@ -187,28 +162,24 @@ inline void sort_accounts(account_t * account,
template <typename Function>
void walk__accounts(const account_t * account,
- Function functor,
- const unsigned int max_depth,
- item_predicate<account_t>& disp_pred_functor)
+ const Function& functor,
+ const unsigned int max_depth)
{
- if (disp_pred_functor(account))
- functor(account, max_depth);
+ functor(account, max_depth);
for (accounts_map::const_iterator i = account->accounts.begin();
i != account->accounts.end();
i++)
- walk__accounts((*i).second, functor, max_depth, disp_pred_functor);
+ walk__accounts((*i).second, functor, max_depth);
}
template <typename Function>
void walk__accounts_sorted(const account_t * account,
- Function functor,
+ const Function& functor,
const unsigned int max_depth,
- const node_t * sort_order,
- item_predicate<account_t>& disp_pred_functor)
+ const node_t * sort_order)
{
- if (disp_pred_functor(account))
- functor(account, max_depth);
+ functor(account, max_depth);
accounts_deque accounts;
@@ -223,12 +194,11 @@ void walk__accounts_sorted(const account_t * account,
for (accounts_deque::const_iterator i = accounts.begin();
i != accounts.end();
i++)
- walk__accounts_sorted(*i, functor, max_depth, sort_order,
- disp_pred_functor);
+ walk__accounts_sorted(*i, functor, max_depth, sort_order);
}
template <typename Function>
-void for_each_account(account_t * account, Function functor)
+void for_each_account(account_t * account, const Function& functor)
{
functor(account);
@@ -255,26 +225,23 @@ inline void sum__accounts(account_t * account)
template <typename Function>
void walk_accounts(account_t * account,
- Function functor,
+ const Function& functor,
const node_t * predicate,
unsigned int flags,
const bool calc_subtotals,
const unsigned int max_depth,
- const node_t * display_predicate = NULL,
- const node_t * sort_order = NULL)
+ const node_t * sort_order = NULL)
{
item_predicate<transaction_t> pred_functor(predicate);
- item_predicate<account_t> disp_pred_functor(display_predicate);
calc__accounts(account, pred_functor, flags);
if (calc_subtotals)
sum__accounts(account);
if (sort_order)
- walk__accounts_sorted<Function>(account, functor, max_depth, sort_order,
- disp_pred_functor);
+ walk__accounts_sorted<Function>(account, functor, max_depth, sort_order);
else
- walk__accounts<Function>(account, functor, max_depth, disp_pred_functor);
+ walk__accounts<Function>(account, functor, max_depth);
}
} // namespace ledger