diff options
-rw-r--r-- | format.cc | 113 | ||||
-rw-r--r-- | format.h | 92 | ||||
-rw-r--r-- | ledger.h | 5 | ||||
-rw-r--r-- | main.cc | 147 | ||||
-rw-r--r-- | valexpr.cc | 16 | ||||
-rw-r--r-- | valexpr.h | 16 | ||||
-rw-r--r-- | walk.h | 4 |
7 files changed, 162 insertions, 231 deletions
@@ -14,18 +14,22 @@ std::string truncated(const std::string& str, unsigned int width) return buf; } -std::string partial_account_name(const account_t * account, - const unsigned int start_depth) +std::string partial_account_name(const account_t * account) { - std::string name = account->name; - const account_t * acct = account->parent; - - for (int i = account->depth - start_depth - 1; - --i >= 0 && acct->parent; ) { - assert(acct); - name = acct->name + ":" + name; - acct = acct->parent; + std::string name; + + for (const account_t * acct = account; + acct && acct->parent; + acct = acct->parent) { + if (acct->flags & ACCOUNT_DISPLAYED) + break; + + if (name.empty()) + name = acct->name; + else + name = acct->name + ":" + name; } + return name; } @@ -206,8 +210,7 @@ void format_t::format_elements(std::ostream& out, if (details.account) { std::string name = (elem->type == element_t::ACCOUNT_FULLNAME ? details.account->fullname() : - partial_account_name(details.account, - details.depth)); + partial_account_name(details.account)); if (elem->max_width > 0) name = truncated(name, elem->max_width); @@ -278,12 +281,15 @@ void format_t::format_elements(std::ostream& out, } case element_t::SPACER: - for (unsigned int i = 0; i < details.depth; i++) { - if (elem->min_width > 0 || elem->max_width > 0) - out.width(elem->min_width > elem->max_width ? - elem->min_width : elem->max_width); - out << " "; - } + for (const account_t * acct = details.account; + acct; + acct = acct->parent) + if (acct->flags & ACCOUNT_DISPLAYED) { + if (elem->min_width > 0 || elem->max_width > 0) + out.width(elem->min_width > elem->max_width ? + elem->min_width : elem->max_width); + out << " "; + } break; default: @@ -293,11 +299,12 @@ void format_t::format_elements(std::ostream& out, } } +#ifdef COLLAPSED_REGISTER + 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)); + first_line_format.format_elements(output_stream, details_t(last_xact)); return; } @@ -321,9 +328,8 @@ void format_transaction::report_cumulative_subtotal() const 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_line_format.format_elements(output_stream, + details_t(&splits_total)); first = false; } else { next_lines_format.format_elements(output_stream, @@ -332,10 +338,12 @@ void format_transaction::report_cumulative_subtotal() const } } +#endif // COLLAPSED_REGISTER + void format_transaction::operator()(transaction_t * xact) const { if (last_xact) - xact->total = last_xact->total; + xact->total += last_xact->total; if (inverted) { xact->amount.negate(); @@ -353,6 +361,7 @@ void format_transaction::operator()(transaction_t * xact) const // This makes the assumption that transactions from a single entry // are always grouped together. +#ifdef COLLAPSED_REGISTER if (collapsed) { // If we've reached a new entry, report on the subtotal // accumulated thus far. @@ -365,10 +374,11 @@ void format_transaction::operator()(transaction_t * xact) const subtotal += *xact; count++; - } else { + } else +#endif + { if (last_entry != xact->entry) { - if (! intercept || ! intercept(xact)) - first_line_format.format_elements(output_stream, details_t(xact)); + first_line_format.format_elements(output_stream, details_t(xact)); } else { next_lines_format.format_elements(output_stream, details_t(xact)); } @@ -383,38 +393,8 @@ void format_transaction::operator()(transaction_t * xact) const 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, +void format_account::operator()(account_t * account, const unsigned int max_depth, const bool report_top) const { @@ -425,7 +405,8 @@ void format_account::operator()(const account_t * account, // parent account and a lone displayed child, then don't display the // parent." - if (bool output = report_top || account->parent != NULL) { + if (bool output = ((report_top || account->parent != NULL) && + disp_pred_functor(account))) { int counted = 0; bool display = false; @@ -445,17 +426,9 @@ void format_account::operator()(const account_t * account, if (counted == 1 && ! display) output = false; - if (output) { - unsigned int depth = account->depth; - if (max_depth == 0 || depth <= max_depth) { - for (const account_t * acct = account; - depth > 0 && acct && acct != last_account; - acct = acct->parent) - depth--; - - format.format_elements(output_stream, details_t(account, depth)); - last_account = account; - } + if (output && (max_depth == 0 || account->depth <= max_depth)) { + format.format_elements(output_stream, details_t(account)); + account->flags |= ACCOUNT_DISPLAYED; } } } @@ -87,17 +87,17 @@ class format_transaction std::ostream& output_stream; const format_t& first_line_format; const format_t& next_lines_format; +#ifdef COLLAPSED_REGISTER const bool collapsed; +#endif const bool inverted; item_predicate<transaction_t> disp_pred_functor; - typedef bool (*intercept_t)(transaction_t * xact); - - intercept_t intercept; - +#ifdef COLLAPSED_REGISTER mutable balance_pair_t subtotal; mutable unsigned int count; +#endif mutable entry_t * last_entry; mutable transaction_t * last_xact; @@ -106,29 +106,86 @@ class format_transaction const format_t& _first_line_format, const format_t& _next_lines_format, const node_t * display_predicate, +#ifdef COLLAPSED_REGISTER const bool _collapsed = false, - const bool _inverted = false, - intercept_t _intercept = NULL) +#endif + const bool _inverted = false) : output_stream(_output_stream), first_line_format(_first_line_format), next_lines_format(_next_lines_format), - collapsed(_collapsed), inverted(_inverted), - disp_pred_functor(display_predicate), - intercept(_intercept), count(0), +#ifdef COLLAPSED_REGISTER + collapsed(_collapsed), +#endif + inverted(_inverted), disp_pred_functor(display_predicate), +#ifdef COLLAPSED_REGISTER + count(0), +#endif last_entry(NULL), last_xact(NULL) {} - void start() const {} - void finish() const { +#ifdef COLLAPSED_REGISTER + ~format_transaction() { if (subtotal) report_cumulative_subtotal(); } void report_cumulative_subtotal() const; +#endif + 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); + +template <typename Function> +class changed_value_filter +{ + const Function& functor; + + mutable entry_t modified_entry; + mutable transaction_t modified_xact; + mutable transaction_t * last_xact; + + public: + changed_value_filter(const Function& _functor) + : functor(_functor), modified_xact(&modified_entry, NULL), + last_xact(NULL) { + modified_entry.payee = "Commodities revalued"; + } + + ~changed_value_filter() { + (*this)(NULL); + } + + void operator()(transaction_t * xact) const { + if (last_xact) { + balance_t prev_bal, cur_bal; + + format_t::compute_total(prev_bal, details_t(last_xact)); + + std::time_t current = xact ? xact->entry->date : std::time(NULL); + std::time_t prev_date = last_xact->entry->date; + last_xact->entry->date = current; + format_t::compute_total(cur_bal, details_t(last_xact)); + last_xact->entry->date = prev_date; + + if (balance_t diff = cur_bal - prev_bal) { + modified_entry.date = current; + + // jww (2004-08-07): What if there are multiple commodities? + assert(diff.amounts.size() == 1); + modified_xact.amount = diff.amount(); + modified_xact.total = diff; + modified_xact.total.negate(); + + functor(&modified_xact); + } + } + + if (xact) + functor(xact); + + last_xact = xact; + } +}; class format_account @@ -138,19 +195,14 @@ class format_account item_predicate<account_t> disp_pred_functor; - mutable const account_t * last_account; - public: 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 {} + disp_pred_functor(display_predicate) {} - void operator()(const account_t * account, + void operator()(account_t * account, const unsigned int max_depth = 1, const bool report_top = false) const; }; @@ -94,6 +94,8 @@ class entry_t }; +#define ACCOUNT_DISPLAYED 0x1 + typedef std::map<const std::string, account_t *> accounts_map; typedef std::pair<const std::string, account_t *> accounts_pair; @@ -109,6 +111,7 @@ class account_t balance_pair_t value; balance_pair_t total; unsigned long ident; + unsigned long flags; mutable std::string _fullname; static unsigned long next_ident; @@ -117,7 +120,7 @@ class account_t const std::string& _name = "", const std::string& _note = "") : parent(_parent), name(_name), note(_note), - depth(parent ? parent->depth + 1 : 0) {} + depth(parent ? parent->depth + 1 : 0), flags(0) {} ~account_t(); @@ -11,19 +11,8 @@ namespace ledger { - -////////////////////////////////////////////////////////////////////// -// -// The command-line balance report -// - static const std::string bal_fmt = "%20T %2_%-n\n"; -////////////////////////////////////////////////////////////////////// -// -// The command-line register and print report -// - static const std::string reg_fmt = "%10d %-.20p %-.22N %12.66t %12.80T\n\ %/ %-.22N %12.66t %12.80T\n"; @@ -31,104 +20,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"; -#if 0 - -static void report_value_change(std::ostream& out, - const std::time_t date, - const balance_pair_t& balance, - const balance_pair_t& prev_balance, - const node_t * predicate, - const format_t& first_line_format, - const format_t& next_lines_format) -{ -} - -void register_report(std::ostream& out, - item_t * top, - const node_t * predicate, - const node_t * sort_order, - const format_t& first_line_format, - const format_t& next_lines_format, - const bool show_expanded) -{ - if (sort_order) - top->sort(sort_order); - - balance_pair_t balance; - balance_pair_t last_reported; - account_t splits(NULL, "<Total>"); - value_predicate pred_obj(predicate); - - for (items_deque::const_iterator i = top->subitems.begin(); - i != top->subitems.end(); - i++) { - bool first = true; - - if ((*i)->subitems.size() > 1 && ! show_expanded) { - item_t summary(*i); - summary.parent = *i; - summary.account = &splits; - - summary.value = 0; - for (items_deque::const_iterator j = (*i)->subitems.begin(); - j != (*i)->subitems.end(); - j++) - summary.value += (*j)->value; - summary.total = balance + summary.value; - - bool show = pred_obj(&summary); - if (show && show_commodities_revalued) - report_value_change(out, summary.date, balance, last_reported, - predicate, first_line_format, next_lines_format); - - balance += summary.value; - - if (show) { - if (! show_commodities_revalued_only) - first_line_format.format_elements(out, &summary, top); - - if (show_commodities_revalued) - last_reported = balance; - } - } else { - for (items_deque::const_iterator j = (*i)->subitems.begin(); - j != (*i)->subitems.end(); - j++) { - (*j)->total = balance + (*j)->value; - - bool show = pred_obj(*j); - if (show && first && show_commodities_revalued) { - report_value_change(out, (*i)->date, balance, last_reported, - predicate, first_line_format, next_lines_format); - if (show_commodities_revalued_only) - first = false; - } - - balance += (*j)->value; - - if (show) { - if (! show_commodities_revalued_only) { - if (first) { - first = false; - first_line_format.format_elements(out, *j, *i); - } else { - next_lines_format.format_elements(out, *j, *i); - } - } - - if (show_commodities_revalued) - last_reported = balance; - } - } - } - } - - if (show_commodities_revalued) - report_value_change(out, -1, balance, last_reported, predicate, - first_line_format, next_lines_format); -} - -#endif void set_price_conversion(const std::string& setting) { @@ -710,18 +601,17 @@ int main(int argc, char * argv[]) unsigned int xact_display_flags = MATCHING_TRANSACTIONS; - if (command == "p" || command == "e") { - show_expanded = true; - } - else if (command == "E") { + if (command == "p" || command == "e" || command == "E") { + xact_display_flags |= OTHER_TRANSACTIONS; show_expanded = true; } - else if (show_related && command == "r") { - xact_display_flags = OTHER_TRANSACTIONS; - show_inverted = true; - } else if (show_related) { - xact_display_flags |= OTHER_TRANSACTIONS; + if (command == "r") { + xact_display_flags = OTHER_TRANSACTIONS; + show_inverted = true; + } else { + xact_display_flags |= OTHER_TRANSACTIONS; + } } const char * f; @@ -737,11 +627,9 @@ int main(int argc, char * argv[]) if (command == "b") { format_t format(f); 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)) { @@ -766,12 +654,20 @@ int main(int argc, char * argv[]) format_transaction formatter(std::cout, format, nformat, display_predicate.get(), - ! show_subtotals, show_inverted); - formatter.start(); - +#ifdef COLLAPSED_REGISTER + ! show_subtotals, +#endif + show_inverted); if (! sort_order.get()) { - walk_entries(journal->entries.begin(), journal->entries.end(), - formatter, predicate.get(), xact_display_flags); + if (show_commodities_revalued) { + changed_value_filter<format_transaction> + filtered_formatter(formatter); + walk_entries(journal->entries.begin(), journal->entries.end(), + filtered_formatter, predicate.get(), xact_display_flags); + } else { + walk_entries(journal->entries.begin(), journal->entries.end(), + formatter, predicate.get(), xact_display_flags); + } } else { transactions_deque transactions_pool; walk_entries(journal->entries.begin(), journal->entries.end(), @@ -782,7 +678,6 @@ int main(int argc, char * argv[]) walk_transactions(transactions_pool.begin(), transactions_pool.end(), formatter); } - formatter.finish(); } // Save the cache, if need be @@ -153,6 +153,8 @@ void node_t::compute(balance_t& result, const details_t& details) const case DATE: if (details.entry) result = (unsigned int) details.entry->date; + else + result = (unsigned int) std::time(NULL); break; case CLEARED: @@ -207,12 +209,20 @@ void node_t::compute(balance_t& result, const details_t& details) const left->compute(result, details); std::time_t moment = -1; - if (right && details.entry) { + if (right) { switch (right->type) { - case DATE: moment = details.entry->date; break; + case DATE: + if (details.entry) + moment = details.entry->date; + else + moment = std::time(NULL); + break; + default: - throw compute_error("Invalid date passed to P(v,d)"); + throw compute_error("Invalid date passed to P(value,date)"); } + } else { + moment = std::time(NULL); } result = result.value(moment); break; @@ -30,20 +30,18 @@ bool matches(const masks_list& regexps, const std::string& str, struct details_t { - const entry_t * entry; - const transaction_t * xact; - const account_t * account; - const unsigned int depth; + const entry_t * entry; + const transaction_t * xact; + const account_t * account; details_t(const entry_t * _entry) - : entry(_entry), xact(NULL), account(NULL), depth(0) {} + : entry(_entry), xact(NULL), account(NULL) {} details_t(const transaction_t * _xact) - : entry(_xact->entry), xact(_xact), account(_xact->account), depth(0) {} + : entry(_xact->entry), xact(_xact), account(_xact->account) {} - details_t(const account_t * _account, - const unsigned int _depth = 0) - : entry(NULL), xact(NULL), account(_account), depth(_depth) {} + details_t(const account_t * _account) + : entry(NULL), xact(NULL), account(_account) {} }; struct node_t @@ -161,7 +161,7 @@ inline void sort_accounts(account_t * account, } template <typename Function> -void walk__accounts(const account_t * account, +void walk__accounts(account_t * account, const Function& functor, const unsigned int max_depth) { @@ -174,7 +174,7 @@ void walk__accounts(const account_t * account, } template <typename Function> -void walk__accounts_sorted(const account_t * account, +void walk__accounts_sorted(account_t * account, const Function& functor, const unsigned int max_depth, const node_t * sort_order) |