Merge branch 'next'
This commit is contained in:
commit
7fae606d62
12 changed files with 190 additions and 121 deletions
|
|
@ -38,10 +38,8 @@
|
||||||
|
|
||||||
namespace ledger {
|
namespace ledger {
|
||||||
|
|
||||||
namespace {
|
|
||||||
template <typename T>
|
|
||||||
void push_sort_value(std::list<sort_value_t>& sort_values,
|
void push_sort_value(std::list<sort_value_t>& sort_values,
|
||||||
expr_t::ptr_op_t node, T * scope)
|
expr_t::ptr_op_t node, scope_t& scope)
|
||||||
{
|
{
|
||||||
if (node->kind == expr_t::op_t::O_CONS) {
|
if (node->kind == expr_t::op_t::O_CONS) {
|
||||||
push_sort_value(sort_values, node->left(), scope);
|
push_sort_value(sort_values, node->left(), scope);
|
||||||
|
|
@ -57,21 +55,13 @@ namespace {
|
||||||
|
|
||||||
sort_values.push_back(sort_value_t());
|
sort_values.push_back(sort_value_t());
|
||||||
sort_values.back().inverted = inverted;
|
sort_values.back().inverted = inverted;
|
||||||
sort_values.back().value = expr_t(node).calc(*scope).simplified();
|
sort_values.back().value = expr_t(node).calc(scope).simplified();
|
||||||
|
|
||||||
if (sort_values.back().value.is_null())
|
if (sort_values.back().value.is_null())
|
||||||
throw_(calc_error,
|
throw_(calc_error,
|
||||||
_("Could not determine sorting value based an expression"));
|
_("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 <>
|
template <>
|
||||||
bool compare_items<post_t>::operator()(post_t * left, post_t * right)
|
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());
|
post_t::xdata_t& lxdata(left->xdata());
|
||||||
if (! lxdata.has_flags(POST_EXT_SORT_CALC)) {
|
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);
|
lxdata.add_flags(POST_EXT_SORT_CALC);
|
||||||
}
|
}
|
||||||
|
|
||||||
post_t::xdata_t& rxdata(right->xdata());
|
post_t::xdata_t& rxdata(right->xdata());
|
||||||
if (! rxdata.has_flags(POST_EXT_SORT_CALC)) {
|
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);
|
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());
|
account_t::xdata_t& lxdata(left->xdata());
|
||||||
if (! lxdata.has_flags(ACCOUNT_EXT_SORT_CALC)) {
|
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);
|
lxdata.add_flags(ACCOUNT_EXT_SORT_CALC);
|
||||||
}
|
}
|
||||||
|
|
||||||
account_t::xdata_t& rxdata(right->xdata());
|
account_t::xdata_t& rxdata(right->xdata());
|
||||||
if (! rxdata.has_flags(ACCOUNT_EXT_SORT_CALC)) {
|
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);
|
rxdata.add_flags(ACCOUNT_EXT_SORT_CALC);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -53,6 +53,9 @@ namespace ledger {
|
||||||
class post_t;
|
class post_t;
|
||||||
class account_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
|
* @brief Brief
|
||||||
*
|
*
|
||||||
|
|
@ -76,7 +79,9 @@ public:
|
||||||
TRACE_DTOR(compare_items);
|
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);
|
bool operator()(T * left, T * right);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -173,6 +173,41 @@ account_t * basic_accounts_iterator::operator()()
|
||||||
return account;
|
return account;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void sorted_accounts_iterator::push_back(account_t& account)
|
||||||
|
{
|
||||||
|
accounts_list.push_back(accounts_deque_t());
|
||||||
|
|
||||||
|
if (flatten_all) {
|
||||||
|
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 (flat): " << account->fullname());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
sort_accounts(account, accounts_list.back());
|
||||||
|
}
|
||||||
|
|
||||||
|
sorted_accounts_i.push_back(accounts_list.back().begin());
|
||||||
|
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,
|
void sorted_accounts_iterator::sort_accounts(account_t& account,
|
||||||
accounts_deque_t& deque)
|
accounts_deque_t& deque)
|
||||||
{
|
{
|
||||||
|
|
@ -190,39 +225,6 @@ void sorted_accounts_iterator::sort_accounts(account_t& account,
|
||||||
#endif
|
#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);
|
|
||||||
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());
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
} else {
|
|
||||||
sort_accounts(account, accounts_list.back());
|
|
||||||
}
|
|
||||||
|
|
||||||
sorted_accounts_i.push_back(accounts_list.back().begin());
|
|
||||||
sorted_accounts_end.push_back(accounts_list.back().end());
|
|
||||||
}
|
|
||||||
|
|
||||||
account_t * sorted_accounts_iterator::operator()()
|
account_t * sorted_accounts_iterator::operator()()
|
||||||
{
|
{
|
||||||
while (! sorted_accounts_i.empty() &&
|
while (! sorted_accounts_i.empty() &&
|
||||||
|
|
|
||||||
|
|
@ -255,12 +255,8 @@ class sorted_accounts_iterator : public accounts_iterator
|
||||||
std::list<accounts_deque_t::const_iterator> sorted_accounts_end;
|
std::list<accounts_deque_t::const_iterator> sorted_accounts_end;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
sorted_accounts_iterator(const expr_t& _sort_cmp, bool _flatten_all)
|
sorted_accounts_iterator(account_t& account,
|
||||||
: sort_cmp(_sort_cmp), flatten_all(_flatten_all) {
|
const expr_t& _sort_cmp, bool _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)
|
|
||||||
: sort_cmp(_sort_cmp), flatten_all(_flatten_all) {
|
: sort_cmp(_sort_cmp), flatten_all(_flatten_all) {
|
||||||
TRACE_CTOR(sorted_accounts_iterator, "const expr_t&, bool, account_t&");
|
TRACE_CTOR(sorted_accounts_iterator, "const expr_t&, bool, account_t&");
|
||||||
push_back(account);
|
push_back(account);
|
||||||
|
|
@ -269,9 +265,9 @@ public:
|
||||||
TRACE_DTOR(sorted_accounts_iterator);
|
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_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()();
|
virtual account_t * operator()();
|
||||||
};
|
};
|
||||||
|
|
|
||||||
15
src/main.cc
15
src/main.cc
|
|
@ -37,21 +37,6 @@
|
||||||
|
|
||||||
using namespace ledger;
|
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
|
#ifdef HAVE_BOOST_PYTHON
|
||||||
namespace ledger {
|
namespace ledger {
|
||||||
extern char * argv0;
|
extern char * argv0;
|
||||||
|
|
|
||||||
|
|
@ -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.xdata().has_flags(ACCOUNT_EXT_TO_DISPLAY) &&
|
||||||
if (account.parent &&
|
! 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_TO_DISPLAY) &&
|
||||||
! account.parent->xdata().has_flags(ACCOUNT_EXT_DISPLAYED))
|
! account.parent->xdata().has_flags(ACCOUNT_EXT_DISPLAYED))
|
||||||
post_account(*account.parent);
|
post_account(*account.parent, flat);
|
||||||
|
|
||||||
account.xdata().add_flags(ACCOUNT_EXT_DISPLAYED);
|
account.xdata().add_flags(ACCOUNT_EXT_DISPLAYED);
|
||||||
|
|
||||||
|
|
@ -207,7 +208,7 @@ void format_accounts::flush()
|
||||||
std::size_t displayed = 0;
|
std::size_t displayed = 0;
|
||||||
|
|
||||||
foreach (account_t * account, posted_accounts)
|
foreach (account_t * account, posted_accounts)
|
||||||
displayed += post_account(*account);
|
displayed += post_account(*account, report.HANDLED(flat));
|
||||||
|
|
||||||
if (displayed > 1 &&
|
if (displayed > 1 &&
|
||||||
! report.HANDLED(no_total) && ! report.HANDLED(percent)) {
|
! report.HANDLED(no_total) && ! report.HANDLED(percent)) {
|
||||||
|
|
@ -221,6 +222,7 @@ void format_accounts::flush()
|
||||||
|
|
||||||
void format_accounts::operator()(account_t& account)
|
void format_accounts::operator()(account_t& account)
|
||||||
{
|
{
|
||||||
|
DEBUG("account.display", "Posting account: " << account.fullname());
|
||||||
posted_accounts.push_back(&account);
|
posted_accounts.push_back(&account);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -109,7 +109,7 @@ public:
|
||||||
std::pair<std::size_t, std::size_t>
|
std::pair<std::size_t, std::size_t>
|
||||||
mark_accounts(account_t& account, const bool flat);
|
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 flush();
|
||||||
|
|
||||||
virtual void operator()(account_t& account);
|
virtual void operator()(account_t& account);
|
||||||
|
|
|
||||||
|
|
@ -81,11 +81,14 @@ void report_t::accounts_report(acct_handler_ptr handler)
|
||||||
true), walker);
|
true), walker);
|
||||||
|
|
||||||
scoped_ptr<accounts_iterator> iter;
|
scoped_ptr<accounts_iterator> iter;
|
||||||
if (! HANDLED(sort_))
|
if (! HANDLED(sort_)) {
|
||||||
iter.reset(new basic_accounts_iterator(*session.master));
|
iter.reset(new basic_accounts_iterator(*session.master));
|
||||||
else
|
} else {
|
||||||
iter.reset(new sorted_accounts_iterator(HANDLER(sort_).str(),
|
expr_t sort_expr(HANDLER(sort_).str());
|
||||||
HANDLED(flat), *session.master.get()));
|
sort_expr.set_context(this);
|
||||||
|
iter.reset(new sorted_accounts_iterator(*session.master.get(),
|
||||||
|
sort_expr, HANDLED(flat)));
|
||||||
|
}
|
||||||
|
|
||||||
if (HANDLED(display_))
|
if (HANDLED(display_))
|
||||||
pass_down_accounts(handler, *iter.get(),
|
pass_down_accounts(handler, *iter.get(),
|
||||||
|
|
@ -408,6 +411,14 @@ value_t report_t::reload_command(call_scope_t&)
|
||||||
return true;
|
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)
|
bool report_t::maybe_import(const string& module)
|
||||||
{
|
{
|
||||||
if (lookup(string(OPT_PREFIX) + "import_")) {
|
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"))
|
else if (is_eq(q, "emacs"))
|
||||||
return WRAP_FUNCTOR
|
return WRAP_FUNCTOR
|
||||||
(reporter<>(new format_emacs_posts(output_stream), *this, "#emacs"));
|
(reporter<>(new format_emacs_posts(output_stream), *this, "#emacs"));
|
||||||
|
else if (is_eq(q, "echo"))
|
||||||
|
return MAKE_FUNCTOR(report_t::echo_command);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'p':
|
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);
|
return MAKE_FUNCTOR(report_t::fn_total_expr);
|
||||||
else if (is_eq(p, "today"))
|
else if (is_eq(p, "today"))
|
||||||
return MAKE_FUNCTOR(report_t::fn_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;
|
break;
|
||||||
|
|
||||||
case 'u':
|
case 'u':
|
||||||
|
|
|
||||||
|
|
@ -178,6 +178,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
value_t reload_command(call_scope_t&);
|
value_t reload_command(call_scope_t&);
|
||||||
|
value_t echo_command(call_scope_t& scope);
|
||||||
|
|
||||||
keep_details_t what_to_keep() {
|
keep_details_t what_to_keep() {
|
||||||
bool lots = HANDLED(lots) || HANDLED(lots_actual);
|
bool lots = HANDLED(lots) || HANDLED(lots_actual);
|
||||||
|
|
|
||||||
|
|
@ -461,7 +461,8 @@ void instance_t::price_xact_directive(char * line)
|
||||||
{
|
{
|
||||||
optional<price_point_t> point =
|
optional<price_point_t> point =
|
||||||
amount_t::current_pool->parse_price_directive(skip_ws(line + 1));
|
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)
|
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_SINGLE) |
|
||||||
static_cast<uint_least8_t>(expr_t::PARSE_NO_MIGRATE));
|
static_cast<uint_least8_t>(expr_t::PARSE_NO_MIGRATE));
|
||||||
|
|
||||||
if (post->assigned_amount->is_null())
|
if (post->assigned_amount->is_null()) {
|
||||||
throw parse_error(_("An assigned balance must evaluate to a constant value"));
|
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 << ": "
|
DEBUG("textual.parse", "line " << linenum << ": "
|
||||||
<< "POST assign: parsed amt = " << *post->assigned_amount);
|
<< "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)
|
value_t account_total(post->account->self_total(false)
|
||||||
.strip_annotations(keep_details_t()));
|
.strip_annotations(keep_details_t()));
|
||||||
|
|
||||||
DEBUG("post.assign", "line " << linenum << ": "
|
DEBUG("post.assign",
|
||||||
"account balance = " << account_total);
|
"line " << linenum << ": " "account balance = " << account_total);
|
||||||
DEBUG("post.assign", "line " << linenum << ": "
|
DEBUG("post.assign",
|
||||||
"post amount = " << amt);
|
"line " << linenum << ": " "post amount = " << amt);
|
||||||
|
|
||||||
amount_t diff;
|
amount_t diff = amt;
|
||||||
|
|
||||||
switch (account_total.type()) {
|
switch (account_total.type()) {
|
||||||
case value_t::AMOUNT:
|
case value_t::AMOUNT:
|
||||||
diff = amt - account_total.as_amount();
|
diff -= account_total.as_amount();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case value_t::BALANCE:
|
case value_t::BALANCE:
|
||||||
if (optional<amount_t> comm_bal =
|
if (optional<amount_t> comm_bal =
|
||||||
account_total.as_balance().commodity_amount(amt.commodity()))
|
account_total.as_balance().commodity_amount(amt.commodity()))
|
||||||
diff = amt - *comm_bal;
|
diff -= *comm_bal;
|
||||||
else
|
|
||||||
diff = amt;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
diff = amt;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUG("post.assign", "line " << linenum << ": "
|
DEBUG("post.assign",
|
||||||
<< "diff = " << diff);
|
"line " << linenum << ": " << "diff = " << diff);
|
||||||
DEBUG("textual.parse", "line " << linenum << ": "
|
DEBUG("textual.parse",
|
||||||
<< "POST assign: diff = " << diff);
|
"line " << linenum << ": " << "POST assign: diff = " << diff);
|
||||||
|
|
||||||
if (! diff.is_zero()) {
|
if (! diff.is_zero()) {
|
||||||
if (! post->amount.is_null()) {
|
if (! post->amount.is_null()) {
|
||||||
diff -= post->amount;
|
diff -= post->amount;
|
||||||
if (! diff.is_zero()) {
|
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,
|
post_t * temp = new post_t(post->account, diff,
|
||||||
ITEM_GENERATED | POST_CALCULATED);
|
ITEM_GENERATED | POST_CALCULATED);
|
||||||
xact->add_post(temp);
|
xact->add_post(temp);
|
||||||
|
|
||||||
DEBUG("textual.parse", "line " << linenum << ": "
|
DEBUG("textual.parse", "line " << linenum << ": "
|
||||||
<< "Created balancing posting");
|
<< "Created balancing posting");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
post->amount = diff;
|
post->amount = diff;
|
||||||
|
|
@ -1032,7 +1041,7 @@ post_t * instance_t::parse_post(char * line,
|
||||||
else
|
else
|
||||||
next = skip_ws(p + static_cast<std::ptrdiff_t>(stream.tellg()));
|
next = skip_ws(p + static_cast<std::ptrdiff_t>(stream.tellg()));
|
||||||
} else {
|
} else {
|
||||||
throw parse_error(_("Expected an assigned balance amount"));
|
throw parse_error(_("Expected an balance assignment/assertion amount"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
53
src/utils.cc
53
src/utils.cc
|
|
@ -442,6 +442,59 @@ string::~string() throw() {
|
||||||
|
|
||||||
ledger::string empty_string("");
|
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
|
* Logging
|
||||||
|
|
|
||||||
|
|
@ -237,6 +237,8 @@ inline bool operator!=(const string& __lhs, const char* __rhs)
|
||||||
|
|
||||||
extern ledger::string empty_string;
|
extern ledger::string empty_string;
|
||||||
|
|
||||||
|
ledger::strings_list split_arguments(const char * line);
|
||||||
|
|
||||||
#define IF_VERIFY() if (DO_VERIFY())
|
#define IF_VERIFY() if (DO_VERIFY())
|
||||||
|
|
||||||
/*@}*/
|
/*@}*/
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue