summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Wiegley <johnw@newartisans.com>2009-10-26 19:09:24 -0400
committerJohn Wiegley <johnw@newartisans.com>2009-10-26 19:09:24 -0400
commit7fae606d622d8cd463ce5f81f5d7872a4fdebc60 (patch)
treebe5550e492b20c135143c821fbc18cbd63c27060
parent92d1bbbe75df71731d458f5b48bcb0f145428920 (diff)
parent3fdd75fb5b2614f7dab29fd5ad5c9efed6e80b79 (diff)
downloadfork-ledger-7fae606d622d8cd463ce5f81f5d7872a4fdebc60.tar.gz
fork-ledger-7fae606d622d8cd463ce5f81f5d7872a4fdebc60.tar.bz2
fork-ledger-7fae606d622d8cd463ce5f81f5d7872a4fdebc60.zip
Merge branch 'next'
-rw-r--r--src/compare.cc60
-rw-r--r--src/compare.h7
-rw-r--r--src/iterators.cc60
-rw-r--r--src/iterators.h12
-rw-r--r--src/main.cc15
-rw-r--r--src/output.cc12
-rw-r--r--src/output.h2
-rw-r--r--src/report.cc28
-rw-r--r--src/report.h1
-rw-r--r--src/textual.cc45
-rw-r--r--src/utils.cc53
-rw-r--r--src/utils.h2
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())
/*@}*/