From d0ba09f1e0f26fd3f449ca639abb71083ead9243 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Thu, 23 Sep 2004 20:06:00 -0400 Subject: greatly improved the flexibility of the "entry" command; no more bogus 1-liners --- NEWS | 3 ++ journal.cc | 98 +++++++++++++++++++++++++++++++++++++++++++------------------ ledger.h | 8 ++--- ledger.texi | 17 ++++++++++- 4 files changed, 91 insertions(+), 35 deletions(-) diff --git a/NEWS b/NEWS index ec2374ed..dab66ac2 100644 --- a/NEWS +++ b/NEWS @@ -90,6 +90,9 @@ - The use of "+" and "-" in ledger files (to specify permanent regexps) has been removed. +- The "-from" argument is no longer needed with the "entry" command. + It can simply be removed, with no other changes. + - -l now takes a value expression as the "calculation predicate". To mimic the old behavior of "-l \$100", use: -d "T&AT>{\$100}" diff --git a/journal.cc b/journal.cc index 4b0b063a..174bd91a 100644 --- a/journal.cc +++ b/journal.cc @@ -1,6 +1,7 @@ #include "ledger.h" #include "valexpr.h" #include "datetime.h" +#include "error.h" #include "acconf.h" #include @@ -191,6 +192,26 @@ account_t * account_t::find_account(const std::string& name, return account; } +static inline +account_t * find_account_re_(account_t * account, const mask_t& regexp) +{ + if (regexp.match(account->fullname())) + return account; + + for (accounts_map::iterator i = account->accounts.begin(); + i != account->accounts.end(); + i++) + if (account_t * a = find_account_re_((*i).second, regexp)) + return a; + + return NULL; +} + +account_t * journal_t::find_account_re(const std::string& regexp) +{ + return find_account_re_(master, mask_t(regexp)); +} + bool account_t::remove_transaction(transaction_t * xact) { transactions.remove(xact); @@ -314,7 +335,7 @@ bool journal_t::remove_entry(entry_t * entry) } entry_t * journal_t::derive_entry(strings_list::iterator i, - strings_list::iterator end) const + strings_list::iterator end) { std::auto_ptr added(new entry_t); @@ -328,7 +349,7 @@ entry_t * journal_t::derive_entry(strings_list::iterator i, mask_t regexp(*i++); - for (entries_list::const_reverse_iterator j = entries.rbegin(); + for (entries_list::reverse_iterator j = entries.rbegin(); j != entries.rend(); j++) if (regexp.match((*j)->payee)) { @@ -343,13 +364,12 @@ entry_t * journal_t::derive_entry(strings_list::iterator i, if ((*i)[0] == '-' || std::isdigit((*i)[0])) { if (! matching) - throw error("Missing account name for non-matching entry"); + throw error("Could not determine the account to draw from"); transaction_t * m_xact, * xact, * first; m_xact = matching->transactions.front(); - amount_t amt(*i++); - first = xact = new transaction_t(m_xact->account, amt); + first = xact = new transaction_t(m_xact->account, amount_t(*i++)); added->add_transaction(xact); if (xact->amount.commodity().symbol.empty()) @@ -360,18 +380,19 @@ entry_t * journal_t::derive_entry(strings_list::iterator i, xact = new transaction_t(m_xact->account, - first->amount); added->add_transaction(xact); - if (i != end && std::string(*i++) == "-from" && i != end) + if (i != end) if (account_t * acct = find_account(*i)) added->transactions.back()->account = acct; } else { - while (std::string(*i) != "-from") { - mask_t acct_regex(*i++); - + while (i != end) { + std::string& re_pat(*i++); account_t * acct = NULL; commodity_t * cmdty = NULL; if (matching) { - for (transactions_list::iterator x + mask_t acct_regex(re_pat); + + for (transactions_list::const_iterator x = matching->transactions.begin(); x != matching->transactions.end(); x++) { @@ -383,38 +404,37 @@ entry_t * journal_t::derive_entry(strings_list::iterator i, } } - if (! acct) - acct = find_account(acct_regex.pattern); + if (! acct) { + acct = find_account_re(re_pat); + if (acct && acct->transactions.size() > 0) + cmdty = &acct->transactions.back()->amount.commodity(); + } if (! acct) - throw error(std::string("Could not find account name '") + - acct_regex.pattern + "'"); + acct = find_account(re_pat); - if (i == end) - throw error("Too few arguments to 'entry'"); - - amount_t amt(*i++); - transaction_t * xact = new transaction_t(acct, amt); - added->add_transaction(xact); + if (i == end) { + added->add_transaction(new transaction_t(acct)); + goto done; + } + transaction_t * xact = new transaction_t(acct, amount_t(*i++)); if (! xact->amount.commodity()) xact->amount.set_commodity(*cmdty); - } - if (i != end && std::string(*i++) == "-from" && i != end) { - if (account_t * acct = find_account(*i++)) - added->add_transaction(new transaction_t(acct)); - } - else if (! matching) { - throw error("Could not figure out the account to draw from"); + added->add_transaction(xact); } - else { + + if (! matching) { + throw error("Could not determine the account to draw from"); + } else { transaction_t * xact = new transaction_t(matching->transactions.back()->account); added->add_transaction(xact); } } + done: return added.release(); } @@ -443,6 +463,7 @@ bool journal_t::valid() const #ifdef USE_BOOST_PYTHON #include +#include using namespace boost::python; using namespace ledger; @@ -565,6 +586,17 @@ account_t * py_find_account_2(journal_t& journal, const std::string& name, return journal.find_account(name, auto_create); } +#define EXC_TRANSLATOR(type) \ + void exc_translate_ ## type(const type& err) { \ + PyErr_SetString(PyExc_RuntimeError, err.what()); \ + } + +EXC_TRANSLATOR(error) +EXC_TRANSLATOR(compute_error) +EXC_TRANSLATOR(value_expr_error) +EXC_TRANSLATOR(interval_expr_error) +EXC_TRANSLATOR(format_error) +EXC_TRANSLATOR(parse_error) void export_journal() { @@ -669,6 +701,16 @@ void export_journal() .value("CLEARED", entry_t::CLEARED) .value("PENDING", entry_t::PENDING) ; + +#define EXC_TRANSLATE(type) \ + register_exception_translator(&exc_translate_ ## type); + + EXC_TRANSLATE(error); + EXC_TRANSLATE(compute_error); + EXC_TRANSLATE(value_expr_error); + EXC_TRANSLATE(interval_expr_error); + EXC_TRANSLATE(format_error); + EXC_TRANSLATE(parse_error); } #endif // USE_BOOST_PYTHON diff --git a/ledger.h b/ledger.h index 1aef2e3a..7be88463 100644 --- a/ledger.h +++ b/ledger.h @@ -224,17 +224,13 @@ class journal_t accounts_cache.insert(accounts_pair(name, account)); return account; } - account_t * find_account(const std::string& name) const { - // With auto_create false, the other `find_account' will not - // change the object. - return const_cast(this)->find_account(name, false); - } + account_t * find_account_re(const std::string& regexp); bool add_entry(entry_t * entry); bool remove_entry(entry_t * entry); entry_t * derive_entry(strings_list::iterator begin, - strings_list::iterator end) const; + strings_list::iterator end); bool valid() const; }; diff --git a/ledger.texi b/ledger.texi index 88a168b9..3d668f3d 100644 --- a/ledger.texi +++ b/ledger.texi @@ -294,7 +294,22 @@ exit code to 1. There is a shell script in the distribution called ``entry'', which simplifies the task of adding a new entry to your ledger, and then -launches @command{vi} to let you confirm that the entry looks appropriate. +launches @command{vi} to let you confirm that the entry looks +appropriate. + +Here are a few more examples of the entry command, assuming the above +journal entry: + +@example +# Pay $11.00 to first transaction account (food) +ledger entry 4/9 viva 11.00 + +# Pay $11.00 to food from checking +ledger entry 4/9 viva 11.00 checking + +# Pay DM 11.00 to dining, no matter what the entry said +ledger entry 4/9 viva dining "DM 11.00" +@end example @node Options, Format strings, Commands, Running Ledger @section Options -- cgit v1.2.3