diff options
author | John Wiegley <johnw@newartisans.com> | 2009-10-26 19:09:24 -0400 |
---|---|---|
committer | John Wiegley <johnw@newartisans.com> | 2009-10-26 19:09:24 -0400 |
commit | 7fae606d622d8cd463ce5f81f5d7872a4fdebc60 (patch) | |
tree | be5550e492b20c135143c821fbc18cbd63c27060 | |
parent | 92d1bbbe75df71731d458f5b48bcb0f145428920 (diff) | |
parent | 3fdd75fb5b2614f7dab29fd5ad5c9efed6e80b79 (diff) | |
download | fork-ledger-7fae606d622d8cd463ce5f81f5d7872a4fdebc60.tar.gz fork-ledger-7fae606d622d8cd463ce5f81f5d7872a4fdebc60.tar.bz2 fork-ledger-7fae606d622d8cd463ce5f81f5d7872a4fdebc60.zip |
Merge branch 'next'
-rw-r--r-- | src/compare.cc | 60 | ||||
-rw-r--r-- | src/compare.h | 7 | ||||
-rw-r--r-- | src/iterators.cc | 60 | ||||
-rw-r--r-- | src/iterators.h | 12 | ||||
-rw-r--r-- | src/main.cc | 15 | ||||
-rw-r--r-- | src/output.cc | 12 | ||||
-rw-r--r-- | src/output.h | 2 | ||||
-rw-r--r-- | src/report.cc | 28 | ||||
-rw-r--r-- | src/report.h | 1 | ||||
-rw-r--r-- | src/textual.cc | 45 | ||||
-rw-r--r-- | src/utils.cc | 53 | ||||
-rw-r--r-- | src/utils.h | 2 |
12 files changed, 183 insertions, 114 deletions
diff --git a/src/compare.cc b/src/compare.cc index cca22691..65e6a1e3 100644 --- a/src/compare.cc +++ b/src/compare.cc @@ -38,41 +38,31 @@ namespace ledger { -namespace { - template <typename T> - void push_sort_value(std::list<sort_value_t>& sort_values, - expr_t::ptr_op_t node, T * scope) - { - if (node->kind == expr_t::op_t::O_CONS) { - push_sort_value(sort_values, node->left(), scope); - push_sort_value(sort_values, node->right(), scope); - } - else { - bool inverted = false; +void push_sort_value(std::list<sort_value_t>& sort_values, + expr_t::ptr_op_t node, scope_t& scope) +{ + if (node->kind == expr_t::op_t::O_CONS) { + push_sort_value(sort_values, node->left(), scope); + push_sort_value(sort_values, node->right(), scope); + } + else { + bool inverted = false; - if (node->kind == expr_t::op_t::O_NEG) { - inverted = true; - node = node->left(); - } + if (node->kind == expr_t::op_t::O_NEG) { + inverted = true; + node = node->left(); + } - sort_values.push_back(sort_value_t()); - sort_values.back().inverted = inverted; - sort_values.back().value = expr_t(node).calc(*scope).simplified(); + sort_values.push_back(sort_value_t()); + sort_values.back().inverted = inverted; + sort_values.back().value = expr_t(node).calc(scope).simplified(); - if (sort_values.back().value.is_null()) - throw_(calc_error, - _("Could not determine sorting value based an expression")); - } + if (sort_values.back().value.is_null()) + throw_(calc_error, + _("Could not determine sorting value based an expression")); } } -template <typename T> -void compare_items<T>::find_sort_values(std::list<sort_value_t>& sort_values, - T * scope) -{ - push_sort_value(sort_values, sort_order.get_op(), scope); -} - template <> bool compare_items<post_t>::operator()(post_t * left, post_t * right) { @@ -81,13 +71,15 @@ bool compare_items<post_t>::operator()(post_t * left, post_t * right) post_t::xdata_t& lxdata(left->xdata()); if (! lxdata.has_flags(POST_EXT_SORT_CALC)) { - find_sort_values(lxdata.sort_values, left); + bind_scope_t bound_scope(*sort_order.get_context(), *left); + find_sort_values(lxdata.sort_values, bound_scope); lxdata.add_flags(POST_EXT_SORT_CALC); } post_t::xdata_t& rxdata(right->xdata()); if (! rxdata.has_flags(POST_EXT_SORT_CALC)) { - find_sort_values(rxdata.sort_values, right); + bind_scope_t bound_scope(*sort_order.get_context(), *right); + find_sort_values(rxdata.sort_values, bound_scope); rxdata.add_flags(POST_EXT_SORT_CALC); } @@ -102,13 +94,15 @@ bool compare_items<account_t>::operator()(account_t * left, account_t * right) account_t::xdata_t& lxdata(left->xdata()); if (! lxdata.has_flags(ACCOUNT_EXT_SORT_CALC)) { - find_sort_values(lxdata.sort_values, left); + bind_scope_t bound_scope(*sort_order.get_context(), *left); + find_sort_values(lxdata.sort_values, bound_scope); lxdata.add_flags(ACCOUNT_EXT_SORT_CALC); } account_t::xdata_t& rxdata(right->xdata()); if (! rxdata.has_flags(ACCOUNT_EXT_SORT_CALC)) { - find_sort_values(rxdata.sort_values, right); + bind_scope_t bound_scope(*sort_order.get_context(), *right); + find_sort_values(rxdata.sort_values, bound_scope); rxdata.add_flags(ACCOUNT_EXT_SORT_CALC); } diff --git a/src/compare.h b/src/compare.h index e1207bc3..c0a72327 100644 --- a/src/compare.h +++ b/src/compare.h @@ -53,6 +53,9 @@ namespace ledger { class post_t; class account_t; +void push_sort_value(std::list<sort_value_t>& sort_values, + expr_t::ptr_op_t node, scope_t& scope); + /** * @brief Brief * @@ -76,7 +79,9 @@ public: TRACE_DTOR(compare_items); } - void find_sort_values(std::list<sort_value_t>& sort_values, T * scope); + void find_sort_values(std::list<sort_value_t>& sort_values, scope_t& scope) { + push_sort_value(sort_values, sort_order.get_op(), scope); + } bool operator()(T * left, T * right); }; diff --git a/src/iterators.cc b/src/iterators.cc index 63cbb9b2..020f70b0 100644 --- a/src/iterators.cc +++ b/src/iterators.cc @@ -173,46 +173,22 @@ account_t * basic_accounts_iterator::operator()() return account; } -void sorted_accounts_iterator::sort_accounts(account_t& account, - accounts_deque_t& deque) -{ - foreach (accounts_map::value_type& pair, account.accounts) - deque.push_back(pair.second); - - std::stable_sort(deque.begin(), deque.end(), - compare_items<account_t>(sort_cmp)); - -#if defined(DEBUG_ON) - if (SHOW_DEBUG("accounts.sorted")) { - foreach (account_t * account, deque) - DEBUG("accounts.sorted", "Account: " << account->fullname()); - } -#endif -} - -void sorted_accounts_iterator::push_all(account_t& account) -{ - accounts_deque_t& deque(accounts_list.back()); - - foreach (accounts_map::value_type& pair, account.accounts) { - deque.push_back(pair.second); - push_all(*pair.second); - } -} - void sorted_accounts_iterator::push_back(account_t& account) { accounts_list.push_back(accounts_deque_t()); if (flatten_all) { - push_all(account); + push_all(account, accounts_list.back()); + std::stable_sort(accounts_list.back().begin(), accounts_list.back().end(), compare_items<account_t>(sort_cmp)); + #if defined(DEBUG_ON) if (SHOW_DEBUG("accounts.sorted")) { foreach (account_t * account, accounts_list.back()) - DEBUG("accounts.sorted", "Account: " << account->fullname()); + DEBUG("accounts.sorted", + "Account (flat): " << account->fullname()); } #endif } else { @@ -223,6 +199,32 @@ void sorted_accounts_iterator::push_back(account_t& account) sorted_accounts_end.push_back(accounts_list.back().end()); } +void sorted_accounts_iterator::push_all(account_t& account, + accounts_deque_t& deque) +{ + foreach (accounts_map::value_type& pair, account.accounts) { + deque.push_back(pair.second); + push_all(*pair.second, deque); + } +} + +void sorted_accounts_iterator::sort_accounts(account_t& account, + accounts_deque_t& deque) +{ + foreach (accounts_map::value_type& pair, account.accounts) + deque.push_back(pair.second); + + std::stable_sort(deque.begin(), deque.end(), + compare_items<account_t>(sort_cmp)); + +#if defined(DEBUG_ON) + if (SHOW_DEBUG("accounts.sorted")) { + foreach (account_t * account, deque) + DEBUG("accounts.sorted", "Account: " << account->fullname()); + } +#endif +} + account_t * sorted_accounts_iterator::operator()() { while (! sorted_accounts_i.empty() && diff --git a/src/iterators.h b/src/iterators.h index ae2ddaf9..a1563539 100644 --- a/src/iterators.h +++ b/src/iterators.h @@ -255,12 +255,8 @@ class sorted_accounts_iterator : public accounts_iterator std::list<accounts_deque_t::const_iterator> sorted_accounts_end; public: - sorted_accounts_iterator(const expr_t& _sort_cmp, bool _flatten_all) - : sort_cmp(_sort_cmp), flatten_all(_flatten_all) { - TRACE_CTOR(sorted_accounts_iterator, "const expr_t&, bool"); - } - sorted_accounts_iterator(const expr_t& _sort_cmp, bool _flatten_all, - account_t& account) + sorted_accounts_iterator(account_t& account, + const expr_t& _sort_cmp, bool _flatten_all) : sort_cmp(_sort_cmp), flatten_all(_flatten_all) { TRACE_CTOR(sorted_accounts_iterator, "const expr_t&, bool, account_t&"); push_back(account); @@ -269,9 +265,9 @@ public: TRACE_DTOR(sorted_accounts_iterator); } - void sort_accounts(account_t& account, accounts_deque_t& deque); - void push_all(account_t& account); void push_back(account_t& account); + void push_all(account_t& account, accounts_deque_t& deque); + void sort_accounts(account_t& account, accounts_deque_t& deque); virtual account_t * operator()(); }; diff --git a/src/main.cc b/src/main.cc index c9a922af..9f0e8690 100644 --- a/src/main.cc +++ b/src/main.cc @@ -37,21 +37,6 @@ using namespace ledger; -namespace { - strings_list split_arguments(char * line) - { - strings_list args; - - // jww (2009-02-04): This is too naive - for (char * p = std::strtok(line, " \t"); - p; - p = std::strtok(NULL, " \t")) - args.push_back(p); - - return args; - } -} - #ifdef HAVE_BOOST_PYTHON namespace ledger { extern char * argv0; diff --git a/src/output.cc b/src/output.cc index 92824714..a0c2581b 100644 --- a/src/output.cc +++ b/src/output.cc @@ -136,13 +136,14 @@ format_accounts::format_accounts(report_t& _report, } } -std::size_t format_accounts::post_account(account_t& account) +std::size_t format_accounts::post_account(account_t& account, const bool flat) { - if (account.xdata().has_flags(ACCOUNT_EXT_TO_DISPLAY)) { - if (account.parent && + if (account.xdata().has_flags(ACCOUNT_EXT_TO_DISPLAY) && + ! account.xdata().has_flags(ACCOUNT_EXT_DISPLAYED)) { + if (! flat && account.parent && account.parent->xdata().has_flags(ACCOUNT_EXT_TO_DISPLAY) && ! account.parent->xdata().has_flags(ACCOUNT_EXT_DISPLAYED)) - post_account(*account.parent); + post_account(*account.parent, flat); account.xdata().add_flags(ACCOUNT_EXT_DISPLAYED); @@ -207,7 +208,7 @@ void format_accounts::flush() std::size_t displayed = 0; foreach (account_t * account, posted_accounts) - displayed += post_account(*account); + displayed += post_account(*account, report.HANDLED(flat)); if (displayed > 1 && ! report.HANDLED(no_total) && ! report.HANDLED(percent)) { @@ -221,6 +222,7 @@ void format_accounts::flush() void format_accounts::operator()(account_t& account) { + DEBUG("account.display", "Posting account: " << account.fullname()); posted_accounts.push_back(&account); } diff --git a/src/output.h b/src/output.h index a35d81cd..5e06db9a 100644 --- a/src/output.h +++ b/src/output.h @@ -109,7 +109,7 @@ public: std::pair<std::size_t, std::size_t> mark_accounts(account_t& account, const bool flat); - virtual std::size_t post_account(account_t& account); + virtual std::size_t post_account(account_t& account, const bool flat); virtual void flush(); virtual void operator()(account_t& account); diff --git a/src/report.cc b/src/report.cc index 9c8ad8ba..53426f39 100644 --- a/src/report.cc +++ b/src/report.cc @@ -81,11 +81,14 @@ void report_t::accounts_report(acct_handler_ptr handler) true), walker); scoped_ptr<accounts_iterator> iter; - if (! HANDLED(sort_)) + if (! HANDLED(sort_)) { iter.reset(new basic_accounts_iterator(*session.master)); - else - iter.reset(new sorted_accounts_iterator(HANDLER(sort_).str(), - HANDLED(flat), *session.master.get())); + } else { + expr_t sort_expr(HANDLER(sort_).str()); + sort_expr.set_context(this); + iter.reset(new sorted_accounts_iterator(*session.master.get(), + sort_expr, HANDLED(flat))); + } if (HANDLED(display_)) pass_down_accounts(handler, *iter.get(), @@ -408,6 +411,14 @@ value_t report_t::reload_command(call_scope_t&) return true; } +value_t report_t::echo_command(call_scope_t& scope) +{ + interactive_t args(scope, "s"); + std::ostream& out(output_stream); + out << args.get<string>(0) << std::endl; + return true; +} + bool report_t::maybe_import(const string& module) { if (lookup(string(OPT_PREFIX) + "import_")) { @@ -710,6 +721,8 @@ expr_t::ptr_op_t report_t::lookup(const string& name) else if (is_eq(q, "emacs")) return WRAP_FUNCTOR (reporter<>(new format_emacs_posts(output_stream), *this, "#emacs")); + else if (is_eq(q, "echo")) + return MAKE_FUNCTOR(report_t::echo_command); break; case 'p': @@ -890,6 +903,13 @@ expr_t::ptr_op_t report_t::lookup(const string& name) return MAKE_FUNCTOR(report_t::fn_total_expr); else if (is_eq(p, "today")) return MAKE_FUNCTOR(report_t::fn_today); + else if (is_eq(p, "t")) + return MAKE_FUNCTOR(report_t::fn_display_amount); + break; + + case 'T': + if (is_eq(p, "T")) + return MAKE_FUNCTOR(report_t::fn_display_total); break; case 'u': diff --git a/src/report.h b/src/report.h index 5921a154..f0052128 100644 --- a/src/report.h +++ b/src/report.h @@ -178,6 +178,7 @@ public: } value_t reload_command(call_scope_t&); + value_t echo_command(call_scope_t& scope); keep_details_t what_to_keep() { bool lots = HANDLED(lots) || HANDLED(lots_actual); diff --git a/src/textual.cc b/src/textual.cc index 967e2f1b..56c67ef3 100644 --- a/src/textual.cc +++ b/src/textual.cc @@ -461,7 +461,8 @@ void instance_t::price_xact_directive(char * line) { optional<price_point_t> point = amount_t::current_pool->parse_price_directive(skip_ws(line + 1)); - assert(point); + if (! point) + throw parse_error(_("Pricing entry failed to parse")); } void instance_t::nomarket_directive(char * line) @@ -969,8 +970,12 @@ post_t * instance_t::parse_post(char * line, static_cast<uint_least8_t>(expr_t::PARSE_SINGLE) | static_cast<uint_least8_t>(expr_t::PARSE_NO_MIGRATE)); - if (post->assigned_amount->is_null()) - throw parse_error(_("An assigned balance must evaluate to a constant value")); + if (post->assigned_amount->is_null()) { + if (post->amount.is_null()) + throw parse_error(_("Balance assignment must evaluate to a constant")); + else + throw parse_error(_("Balance assertion must evaluate to a constant")); + } DEBUG("textual.parse", "line " << linenum << ": " << "POST assign: parsed amt = " << *post->assigned_amount); @@ -979,46 +984,50 @@ post_t * instance_t::parse_post(char * line, value_t account_total(post->account->self_total(false) .strip_annotations(keep_details_t())); - DEBUG("post.assign", "line " << linenum << ": " - "account balance = " << account_total); - DEBUG("post.assign", "line " << linenum << ": " - "post amount = " << amt); + DEBUG("post.assign", + "line " << linenum << ": " "account balance = " << account_total); + DEBUG("post.assign", + "line " << linenum << ": " "post amount = " << amt); - amount_t diff; + amount_t diff = amt; switch (account_total.type()) { case value_t::AMOUNT: - diff = amt - account_total.as_amount(); + diff -= account_total.as_amount(); break; case value_t::BALANCE: if (optional<amount_t> comm_bal = account_total.as_balance().commodity_amount(amt.commodity())) - diff = amt - *comm_bal; - else - diff = amt; + diff -= *comm_bal; break; default: - diff = amt; break; } - DEBUG("post.assign", "line " << linenum << ": " - << "diff = " << diff); - DEBUG("textual.parse", "line " << linenum << ": " - << "POST assign: diff = " << diff); + DEBUG("post.assign", + "line " << linenum << ": " << "diff = " << diff); + DEBUG("textual.parse", + "line " << linenum << ": " << "POST assign: diff = " << diff); if (! diff.is_zero()) { if (! post->amount.is_null()) { diff -= post->amount; if (! diff.is_zero()) { +#if 1 + throw_(parse_error, _("Balance assertion off by %1") << diff); +#else + // This code, rather than issuing an error if a balance assignment + // fails, creates a balancing transaction that causes the + // assertion to be true. post_t * temp = new post_t(post->account, diff, ITEM_GENERATED | POST_CALCULATED); xact->add_post(temp); DEBUG("textual.parse", "line " << linenum << ": " << "Created balancing posting"); +#endif } } else { post->amount = diff; @@ -1032,7 +1041,7 @@ post_t * instance_t::parse_post(char * line, else next = skip_ws(p + static_cast<std::ptrdiff_t>(stream.tellg())); } else { - throw parse_error(_("Expected an assigned balance amount")); + throw parse_error(_("Expected an balance assignment/assertion amount")); } } diff --git a/src/utils.cc b/src/utils.cc index 0afea4c2..85a7aa46 100644 --- a/src/utils.cc +++ b/src/utils.cc @@ -442,6 +442,59 @@ string::~string() throw() { ledger::string empty_string(""); +ledger::strings_list split_arguments(const char * line) +{ + using namespace ledger; + + strings_list args; + + char buf[4096]; + char * q = buf; + char in_quoted_string = '\0'; + + for (const char * p = line; *p; p++) { + if (! in_quoted_string && std::isspace(*p)) { + if (q != buf) { + *q = '\0'; + args.push_back(buf); + q = buf; + } + } + else if (in_quoted_string != '\'' && *p == '\\') { + p++; + if (! *p) + throw_(std::logic_error, _("Invalid use of backslash")); + *q++ = *p; + } + else if (in_quoted_string != '"' && *p == '\'') { + if (in_quoted_string == '\'') + in_quoted_string = '\0'; + else + in_quoted_string = '\''; + } + else if (in_quoted_string != '\'' && *p == '"') { + if (in_quoted_string == '"') + in_quoted_string = '\0'; + else + in_quoted_string = '"'; + } + else { + *q++ = *p; + } + } + + if (in_quoted_string) + throw_(std::logic_error, + _("Unterminated string, expected '%1'") << in_quoted_string); + + if (q != buf) { + *q = '\0'; + args.push_back(buf); + } + + return args; +} + /********************************************************************** * * Logging diff --git a/src/utils.h b/src/utils.h index 7f5ca017..98bdf9af 100644 --- a/src/utils.h +++ b/src/utils.h @@ -237,6 +237,8 @@ inline bool operator!=(const string& __lhs, const char* __rhs) extern ledger::string empty_string; +ledger::strings_list split_arguments(const char * line); + #define IF_VERIFY() if (DO_VERIFY()) /*@}*/ |