diff options
Diffstat (limited to 'src/textual.cc')
-rw-r--r-- | src/textual.cc | 86 |
1 files changed, 59 insertions, 27 deletions
diff --git a/src/textual.cc b/src/textual.cc index c97b8b01..3416073b 100644 --- a/src/textual.cc +++ b/src/textual.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2016, John Wiegley. All rights reserved. + * Copyright (c) 2003-2018, John Wiegley. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -567,6 +567,9 @@ void instance_t::automated_xact_directive(char * line) expr_t::ptr_op_t expr = query.parse_args(string_value(skip_ws(line + 1)).to_sequence(), keeper, false, true); + if (!expr) { + throw parse_error(_("Expected predicate after '='")); + } unique_ptr<auto_xact_t> ae(new auto_xact_t(predicate_t(expr, keeper))); ae->pos = position_t(); @@ -725,15 +728,12 @@ void instance_t::include_directive(char * line) if (line[0] != '/' && line[0] != '\\' && line[0] != '~') { DEBUG("textual.include", "received a relative path"); DEBUG("textual.include", "parent file path: " << context.pathname); - string pathstr(context.pathname.string()); - string::size_type pos = pathstr.rfind('/'); - if (pos == string::npos) - pos = pathstr.rfind('\\'); - if (pos != string::npos) { - filename = path(string(pathstr, 0, pos + 1)) / line; - DEBUG("textual.include", "normalized path: " << filename.string()); - } else { + path parent_path = context.pathname.parent_path(); + if (parent_path.empty()) { filename = path(string(".")) / line; + } else { + filename = parent_path / line; + DEBUG("textual.include", "normalized path: " << filename.string()); } } else { filename = line; @@ -1132,6 +1132,7 @@ void instance_t::commodity_format_directive(commodity_t&, string format) trim(format); amount_t amt; amt.parse(format); + amt.commodity().add_flags(COMMODITY_STYLE_NO_MIGRATE); VERIFY(amt.valid()); } @@ -1647,53 +1648,84 @@ post_t * instance_t::parse_post(char * line, } DEBUG("textual.parse", "line " << context.linenum << ": " - << "POST assign: parsed amt = " << *post->assigned_amount); + << "POST assign: parsed balance amount = " << *post->assigned_amount); - amount_t& amt(*post->assigned_amount); + const amount_t& amt(*post->assigned_amount); value_t account_total (post->account->amount().strip_annotations(keep_details_t())); DEBUG("post.assign", "line " << context.linenum << ": " << "account balance = " << account_total); - DEBUG("post.assign", - "line " << context.linenum << ": " << "post amount = " << amt); + DEBUG("post.assign", "line " << context.linenum << ": " + << "post amount = " << amt << " (is_zero = " << amt.is_zero() << ")"); - amount_t diff = amt; + balance_t diff = amt; switch (account_total.type()) { case value_t::AMOUNT: diff -= account_total.as_amount(); + DEBUG("textual.parse", "line " << context.linenum << ": " + << "Subtracting amount " << account_total.as_amount() << " from diff, yielding " << diff); break; case value_t::BALANCE: - if (optional<amount_t> comm_bal = - account_total.as_balance().commodity_amount(amt.commodity())) - diff -= *comm_bal; + diff -= account_total.as_balance(); + DEBUG("textual.parse", "line " << context.linenum << ": " + << "Subtracting balance " << account_total.as_balance() << " from diff, yielding " << diff); break; default: break; } - amount_t tot = amt - diff; - DEBUG("post.assign", "line " << context.linenum << ": " << "diff = " << diff); DEBUG("textual.parse", "line " << context.linenum << ": " << "POST assign: diff = " << diff); - if (! diff.is_zero()) { - if (! post->amount.is_null()) { - diff -= post->amount; - if (! no_assertions && ! diff.is_zero()) - throw_(parse_error, - _f("Balance assertion off by %1% (expected to see %2%)") - % diff % tot); + // Subtract amounts from previous posts to this account in the xact. + for (post_t* p : xact->posts) { + if (p->account == post->account) { + diff -= p->amount; + DEBUG("textual.parse", "line " << context.linenum << ": " + << "Subtracting " << p->amount << ", diff = " << diff); + } + } + + // If amt has a commodity, restrict balancing to that. Otherwise, it's the blanket '0' and + // check that all of them are zero. + if (amt.has_commodity()) { + DEBUG("textual.parse", "line " << context.linenum << ": " + << "Finding commodity " << amt.commodity() << " (" << amt << ") in balance " << diff); + optional<amount_t> wanted_commodity = diff.commodity_amount(amt.commodity()); + if (!wanted_commodity) { + diff = amt - amt; // this is '0' with the correct commodity. } else { - post->amount = diff; + diff = *wanted_commodity; + } + DEBUG("textual.parse", "line " << context.linenum << ": " + << "Diff is now " << diff); + } + + if (post->amount.is_null()) { + // balance assignment + if (! diff.is_zero()) { + // This will fail if there are more than 1 commodity in diff, which is wanted, + // as amount cannot store more than 1 commodity. + post->amount = diff.to_amount(); DEBUG("textual.parse", "line " << context.linenum << ": " << "Overwrite null posting"); } + } else { + // balance assertion + diff -= post->amount; + if (! no_assertions && ! diff.is_zero()) { + balance_t tot = -diff + amt; + DEBUG("textual.parse", "Balance assertion: off by " << diff << " (expected to see " << tot << ")"); + throw_(parse_error, + _f("Balance assertion off by %1% (expected to see %2%)") + % diff.to_string() % tot.to_string()); + } } if (stream.eof()) |