diff options
-rw-r--r-- | amount.cc | 2 | ||||
-rw-r--r-- | format.cc | 124 | ||||
-rw-r--r-- | format.h | 58 | ||||
-rw-r--r-- | ledger.h | 7 | ||||
-rw-r--r-- | main.cc | 56 | ||||
-rw-r--r-- | valexpr.h | 19 | ||||
-rw-r--r-- | walk.h | 91 |
7 files changed, 231 insertions, 126 deletions
@@ -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)); } @@ -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 @@ -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 @@ -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) {} }; @@ -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 @@ -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 @@ -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 |