From ea27d1b45a5ff975a1e90e3e9f4b74ff8d34056e Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Tue, 29 Jul 2008 20:10:03 -0400 Subject: Moved around and renamed a very large amount of code in order to rationalize the way that value expressions extract information from journal objects. --- Makefile.am | 37 +++- account.cc | 141 +++++++++++++++ account.h | 103 +++++++++++ binary.cc | 72 ++++---- csv.cc | 18 +- csv.h | 14 +- derive.cc | 58 +++--- emacs.cc | 14 +- emacs.h | 14 +- entry.cc | 451 ++++++++++++++++++++++++++++++++++++++++++++++ entry.h | 249 +++++++++++++++++++++++++ expr.cc | 17 ++ expr.h | 28 +-- format.cc | 74 ++++---- format.h | 20 +-- gnucash.cc | 30 ++-- hooks.h | 70 ++++++++ journal.cc | 579 +---------------------------------------------------------- journal.h | 436 +------------------------------------------- main.cc | 4 +- main.py | 373 -------------------------------------- ofx.cc | 20 +-- op.cc | 68 +++---- option.cc | 2 +- qif.cc | 24 +-- quotes.cc | 10 +- quotes.h | 5 +- reconcile.cc | 28 +-- reconcile.h | 20 +-- report.cc | 140 +++++++-------- report.h | 2 +- scope.cc | 13 -- scope.h | 2 +- session.cc | 14 +- session.h | 5 +- test.py | 22 --- textual.cc | 151 ++++++++-------- textual.h | 15 +- walk.cc | 340 +++++++++++++++++------------------ walk.h | 549 +++++++++++++++++++++++++++---------------------------- xact.cc | 140 +++++++++++++++ xact.h | 143 +++++++++++++++ xml.cc | 64 +++---- 43 files changed, 2264 insertions(+), 2315 deletions(-) create mode 100644 account.cc create mode 100644 account.h create mode 100644 entry.cc create mode 100644 entry.h create mode 100644 hooks.h delete mode 100644 main.py delete mode 100755 test.py create mode 100644 xact.cc create mode 100644 xact.h diff --git a/Makefile.am b/Makefile.am index 9149847c..2cfc7e8d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,7 +1,23 @@ BUILT_SOURCES = CLEANFILES = -EXTRA_DIST = LICENSE doc test contrib scripts setup.py \ - acprep valgrind.sh version +EXTRA_DIST = LICENSE test scripts setup.py acprep valgrind.sh \ + version sample.dat ledger.vim + +# Files that are still only in the Ledger source tree (g200d919): +# +# amounts.cc +# py_amount.cc +# py_commodity.cc +# py_times.cc +# py_utils.cc +# pyinterp.cc +# pyledger.cc +# +# pyfstream.h +# pyinterp.h +# pyledger.h +# pyutils.h +# tuples.hpp ESC_srcdir=`echo "$(srcdir)" | sed 's/\//\\\\\//g'` ESC_builddir=`echo "$(top_builddir)" | sed 's/\//\\\\\//g'` @@ -47,6 +63,9 @@ libledger_la_SOURCES = \ format.cc \ \ journal.cc \ + entry.cc \ + xact.cc \ + account.cc \ report.cc \ session.cc \ walk.cc \ @@ -59,8 +78,8 @@ libledger_la_SOURCES = \ xml.cc \ derive.cc \ reconcile.cc \ - option.cc -# quotes.cc this is currently not being included + option.cc \ + quotes.cc if HAVE_EXPAT libledger_la_SOURCES += gnucash.cc endif @@ -75,6 +94,7 @@ libledger_la_LDFLAGS = -release 2.7.0 pkginclude_HEADERS = \ acconf.h \ + system.hh \ \ amount.h \ commodity.h \ @@ -82,8 +102,12 @@ pkginclude_HEADERS = \ balpair.h \ value.h \ utils.h \ + fdstream.hpp \ times.h \ mask.h \ + flags.h \ + hooks.h \ + pushvar.h \ error.h \ \ expr.h \ @@ -95,6 +119,9 @@ pkginclude_HEADERS = \ format.h \ \ journal.h \ + entry.h \ + xact.h \ + account.h \ report.h \ session.h \ walk.h \ @@ -105,6 +132,7 @@ pkginclude_HEADERS = \ emacs.h \ gnucash.h \ qif.h \ + ofx.h \ xml.h \ \ derive.h \ @@ -148,6 +176,7 @@ DISTCLEANFILES = ledger.elc timeclock.elc if HAVE_BOOST_PYTHON noinst_PROGRAMS = amounts.so +nodist_amounts_so_SOURCES = amounts.c CLEANFILES += amounts.so diff --git a/account.cc b/account.cc new file mode 100644 index 00000000..0a5ea0dc --- /dev/null +++ b/account.cc @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2003-2008, 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 + * met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of New Artisans LLC nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "account.h" + +namespace ledger { + +account_t::~account_t() +{ + TRACE_DTOR(account_t); + + for (accounts_map::iterator i = accounts.begin(); + i != accounts.end(); + i++) + checked_delete((*i).second); +} + +account_t * account_t::find_account(const string& name, + const bool auto_create) +{ + accounts_map::const_iterator i = accounts.find(name); + if (i != accounts.end()) + return (*i).second; + + char buf[256]; + + string::size_type sep = name.find(':'); + assert(sep < 256|| sep == string::npos); + + const char * first, * rest; + if (sep == string::npos) { + first = name.c_str(); + rest = NULL; + } else { + std::strncpy(buf, name.c_str(), sep); + buf[sep] = '\0'; + + first = buf; + rest = name.c_str() + sep + 1; + } + + account_t * account; + + i = accounts.find(first); + if (i == accounts.end()) { + if (! auto_create) + return NULL; + + account = new account_t(this, first); + std::pair result + = accounts.insert(accounts_map::value_type(first, account)); + assert(result.second); + } else { + account = (*i).second; + } + + if (rest) + account = account->find_account(rest, auto_create); + + return account; +} + +string account_t::fullname() const +{ + if (! _fullname.empty()) { + return _fullname; + } else { + const account_t * first = this; + string fullname = name; + + while (first->parent) { + first = first->parent; + if (! first->name.empty()) + fullname = first->name + ":" + fullname; + } + + _fullname = fullname; + + return fullname; + } +} + +std::ostream& operator<<(std::ostream& out, const account_t& account) +{ + out << account.fullname(); + return out; +} + +bool account_t::valid() const +{ + if (depth > 256) { + DEBUG("ledger.validate", "account_t: depth > 256"); + return false; + } + + for (accounts_map::const_iterator i = accounts.begin(); + i != accounts.end(); + i++) { + if (this == (*i).second) { + DEBUG("ledger.validate", "account_t: parent refers to itself!"); + return false; + } + + if (! (*i).second->valid()) { + DEBUG("ledger.validate", "account_t: child not valid"); + return false; + } + } + + return true; +} + +} // namespace ledger diff --git a/account.h b/account.h new file mode 100644 index 00000000..ba3c6393 --- /dev/null +++ b/account.h @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2003-2008, 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 + * met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of New Artisans LLC nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _ACCOUNT_H +#define _ACCOUNT_H + +#include "utils.h" + +namespace ledger { + +class account_t; + +typedef std::map accounts_map; + +class account_t +{ + public: + typedef unsigned long ident_t; + + account_t * parent; + string name; + optional note; + unsigned short depth; + accounts_map accounts; + + mutable void * data; + mutable ident_t ident; + mutable string _fullname; + + account_t(account_t * _parent = NULL, + const string& _name = "", + const optional& _note = none) + : parent(_parent), name(_name), note(_note), + depth(parent ? parent->depth + 1 : 0), data(NULL), ident(0) { + TRACE_CTOR(account_t, "account_t *, const string&, const string&"); + } + account_t(const account_t& other) + : parent(other.parent), + name(other.name), + note(other.note), + depth(other.depth), + accounts(other.accounts), + data(NULL), + ident(0) { + TRACE_CTOR(account_t, "copy"); + assert(other.data == NULL); + assert(other.ident == 0); + } + ~account_t(); + + operator string() const { + return fullname(); + } + string fullname() const; + + void add_account(account_t * acct) { + accounts.insert(accounts_map::value_type(acct->name, acct)); + } + bool remove_account(account_t * acct) { + accounts_map::size_type n = accounts.erase(acct->name); + return n > 0; + } + + account_t * find_account(const string& name, bool auto_create = true); + + bool valid() const; + + friend class journal_t; +}; + +std::ostream& operator<<(std::ostream& out, const account_t& account); + +} // namespace ledger + +#endif // _ACCOUNT_H diff --git a/binary.cc b/binary.cc index 17d33a96..85b1111c 100644 --- a/binary.cc +++ b/binary.cc @@ -292,7 +292,7 @@ inline void read_mask(const char *& data, mask_t& mask) mask.exclude = exclude; } -inline void read_transaction(const char *& data, transaction_t * xact) +inline void read_xact(const char *& data, xact_t * xact) { read_number(data, xact->_date); read_number(data, xact->_date_eff); @@ -306,10 +306,10 @@ inline void read_transaction(const char *& data, transaction_t * xact) read_amount(data, xact->amount); string str; read_string(data, str); - xact->amount_expr.set_text(str); + xact->amount_expr->set_text(str); } else { - xact->amount_expr.read(data); + xact->amount_expr->read(data); } if (read_bool(data)) { @@ -323,8 +323,8 @@ inline void read_transaction(const char *& data, transaction_t * xact) } read_number(data, xact->state); - xact->set_flags(read_number(data)); - xact->add_flags(TRANSACTION_BULK_ALLOC); + xact->set_flags(read_number(data)); + xact->add_flags(XACT_BULK_ALLOC); read_string(data, xact->note); xact->beg_pos = read_long(data); @@ -341,7 +341,7 @@ inline void read_transaction(const char *& data, transaction_t * xact) } inline void read_entry_base(const char *& data, entry_base_t * entry, - transaction_t *& xact_pool, bool& finalize) + xact_t *& xact_pool, bool& finalize) { read_long(data, entry->src_idx); entry->beg_pos = read_long(data); @@ -354,16 +354,16 @@ inline void read_entry_base(const char *& data, entry_base_t * entry, for (unsigned long i = 0, count = read_long(data); i < count; i++) { - new(xact_pool) transaction_t; - read_transaction(data, xact_pool); - if (ignore_calculated && xact_pool->has_flags(TRANSACTION_CALCULATED)) + new(xact_pool) xact_t; + read_xact(data, xact_pool); + if (ignore_calculated && xact_pool->has_flags(XACT_CALCULATED)) finalize = true; - entry->add_transaction(xact_pool++); + entry->add_xact(xact_pool++); } } inline void read_entry(const char *& data, entry_t * entry, - transaction_t *& xact_pool, bool& finalize) + xact_t *& xact_pool, bool& finalize) { read_entry_base(data, entry, xact_pool, finalize); read_number(data, entry->_date); @@ -373,18 +373,18 @@ inline void read_entry(const char *& data, entry_t * entry, } inline void read_auto_entry(const char *& data, auto_entry_t * entry, - transaction_t *& xact_pool) + xact_t *& xact_pool) { bool ignore; read_entry_base(data, entry, xact_pool, ignore); expr_t expr; expr.read(data); - entry->predicate = item_predicate(expr); + entry->predicate = item_predicate(expr); } inline void read_period_entry(const char *& data, period_entry_t * entry, - transaction_t *& xact_pool, bool& finalize) + xact_t *& xact_pool, bool& finalize) { read_entry_base(data, entry, xact_pool, finalize); read_string(data, &entry->period_string); @@ -589,25 +589,25 @@ void write_mask(std::ostream& out, mask_t& mask) write_string(out, mask.expr.str()); } -void write_transaction(std::ostream& out, transaction_t * xact, +void write_xact(std::ostream& out, xact_t * xact, bool ignore_calculated) { write_number(out, xact->_date); write_number(out, xact->_date_eff); write_long(out, xact->account->ident); - if (ignore_calculated && xact->has_flags(TRANSACTION_CALCULATED)) { + if (ignore_calculated && xact->has_flags(XACT_CALCULATED)) { write_number(out, 0); write_amount(out, amount_t()); } else if (xact->amount_expr) { write_number(out, 2); - xact->amount_expr.write(out); + xact->amount_expr->write(out); } - else if (! xact->amount_expr.text().empty()) { + else if (! xact->amount_expr->text().empty()) { write_number(out, 1); write_amount(out, xact->amount); - write_string(out, xact->amount_expr.text()); + write_string(out, xact->amount_expr->text()); } else { write_number(out, 0); @@ -615,7 +615,7 @@ void write_transaction(std::ostream& out, transaction_t * xact, } if (xact->cost && - (! (ignore_calculated && xact->has_flags(TRANSACTION_CALCULATED)))) { + (! (ignore_calculated && xact->has_flags(XACT_CALCULATED)))) { write_bool(out, true); write_amount(out, *xact->cost); xact->cost_expr->write(out); @@ -642,8 +642,8 @@ void write_entry_base(std::ostream& out, entry_base_t * entry) write_long(out, entry->end_line); bool ignore_calculated = false; - for (transactions_list::const_iterator i = entry->transactions.begin(); - i != entry->transactions.end(); + for (xacts_list::const_iterator i = entry->xacts.begin(); + i != entry->xacts.end(); i++) if ((*i)->amount_expr) { ignore_calculated = true; @@ -652,11 +652,11 @@ void write_entry_base(std::ostream& out, entry_base_t * entry) write_bool(out, ignore_calculated); - write_long(out, entry->transactions.size()); - for (transactions_list::const_iterator i = entry->transactions.begin(); - i != entry->transactions.end(); + write_long(out, entry->xacts.size()); + for (xacts_list::const_iterator i = entry->xacts.begin(); + i != entry->xacts.end(); i++) - write_transaction(out, *i, ignore_calculated); + write_xact(out, *i, ignore_calculated); } void write_entry(std::ostream& out, entry_t * entry) @@ -861,7 +861,7 @@ unsigned int journal_t::read(std::istream& in, if (read_bool(data)) basket = accounts[read_long(data) - 1]; - // Allocate the memory needed for the entries and transactions in + // Allocate the memory needed for the entries and xacts in // one large block, which is then chopped up and custom constructed // as necessary. @@ -872,7 +872,7 @@ unsigned int journal_t::read(std::istream& in, unsigned long bigint_count = read_number(data); std::size_t pool_size = (sizeof(entry_t) * count + - sizeof(transaction_t) * xact_count + + sizeof(xact_t) * xact_count + amount_t::sizeof_bigint_t() * bigint_count); char * item_pool = new char[pool_size]; @@ -881,11 +881,11 @@ unsigned int journal_t::read(std::istream& in, item_pool_end = item_pool + pool_size; entry_t * entry_pool = (entry_t *) item_pool; - transaction_t * xact_pool = (transaction_t *) (item_pool + + xact_t * xact_pool = (xact_t *) (item_pool + sizeof(entry_t) * count); bigints_index = 0; bigints = bigints_next = (item_pool + sizeof(entry_t) * count + - sizeof(transaction_t) * xact_count); + sizeof(xact_t) * xact_count); // Read in the base commodities and then derived commodities @@ -970,7 +970,7 @@ unsigned int journal_t::read(std::istream& in, else amount_t::current_pool->default_commodity = commodities[ident - 1]; - // Read in the entries and transactions + // Read in the entries and xacts for (unsigned long i = 0; i < count; i++) { new(entry_pool) entry_t; @@ -1062,7 +1062,7 @@ void journal_t::write(std::ostream& out) write_bool(out, false); } - // Write out the number of entries, transactions, and amounts + // Write out the number of entries, xacts, and amounts write_long(out, entries.size()); write_long(out, auto_entries.size()); @@ -1126,7 +1126,7 @@ void journal_t::write(std::ostream& out) write_long(out, 0xffffffff); #endif - // Write out the entries and transactions + // Write out the entries and xacts unsigned long xact_count = 0; @@ -1134,21 +1134,21 @@ void journal_t::write(std::ostream& out) i != entries.end(); i++) { write_entry(out, *i); - xact_count += (*i)->transactions.size(); + xact_count += (*i)->xacts.size(); } for (auto_entries_list::const_iterator i = auto_entries.begin(); i != auto_entries.end(); i++) { write_auto_entry(out, *i); - xact_count += (*i)->transactions.size(); + xact_count += (*i)->xacts.size(); } for (period_entries_list::const_iterator i = period_entries.begin(); i != period_entries.end(); i++) { write_period_entry(out, *i); - xact_count += (*i)->transactions.size(); + xact_count += (*i)->xacts.size(); } // Back-patch the count for amounts diff --git a/csv.cc b/csv.cc index 1a0ed2f9..58ffab7d 100644 --- a/csv.cc +++ b/csv.cc @@ -17,10 +17,10 @@ namespace { } } -void format_csv_transactions::operator()(transaction_t& xact) +void format_csv_xacts::operator()(xact_t& xact) { - if (! transaction_has_xdata(xact) || - ! (transaction_xdata_(xact).dflags & TRANSACTION_DISPLAYED)) { + if (! xact_has_xdata(xact) || + ! (xact_xdata_(xact).dflags & XACT_DISPLAYED)) { { format_t fmt("%D"); @@ -73,20 +73,20 @@ void format_csv_transactions::operator()(transaction_t& xact) out << ','; switch (xact.state) { - case transaction_t::CLEARED: + case xact_t::CLEARED: write_escaped_string(out, "*"); break; - case transaction_t::PENDING: + case xact_t::PENDING: write_escaped_string(out, "!"); break; default: { - transaction_t::state_t state; + xact_t::state_t state; if (xact.entry->get_state(&state)) switch (state) { - case transaction_t::CLEARED: + case xact_t::CLEARED: write_escaped_string(out, "*"); break; - case transaction_t::PENDING: + case xact_t::PENDING: write_escaped_string(out, "!"); break; default: @@ -111,7 +111,7 @@ void format_csv_transactions::operator()(transaction_t& xact) } out << '\n'; - transaction_xdata(xact).dflags |= TRANSACTION_DISPLAYED; + xact_xdata(xact).dflags |= XACT_DISPLAYED; } } diff --git a/csv.h b/csv.h index 8ec9b350..f5790243 100644 --- a/csv.h +++ b/csv.h @@ -6,25 +6,25 @@ namespace ledger { -class format_csv_transactions : public item_handler +class format_csv_xacts : public item_handler { - format_csv_transactions(); + format_csv_xacts(); protected: std::ostream& out; public: - format_csv_transactions(std::ostream& _out) : out(_out) { - TRACE_CTOR(format_csv_transactions, "std::ostream&"); + format_csv_xacts(std::ostream& _out) : out(_out) { + TRACE_CTOR(format_csv_xacts, "std::ostream&"); } - ~format_csv_transactions() { - TRACE_DTOR(format_csv_transactions); + ~format_csv_xacts() { + TRACE_DTOR(format_csv_xacts); } virtual void flush() { out.flush(); } - virtual void operator()(transaction_t& xact); + virtual void operator()(xact_t& xact); }; } // namespace ledger diff --git a/derive.cc b/derive.cc index 181dcc86..9f6aeca8 100644 --- a/derive.cc +++ b/derive.cc @@ -53,10 +53,10 @@ entry_t * derive_new_entry(report_t& report, } if (i == end) { - added->add_transaction(new transaction_t(acct)); + added->add_xact(new xact_t(acct)); } else { - transaction_t * xact = new transaction_t(acct, amount_t(*i++)); - added->add_transaction(xact); + xact_t * xact = new xact_t(acct, amount_t(*i++)); + added->add_xact(xact); if (! xact->amount.commodity()) { // If the amount has no commodity, we can determine it given @@ -89,39 +89,39 @@ entry_t * derive_new_entry(report_t& report, acct = session.find_account("Equity"); } - added->add_transaction(new transaction_t(acct)); + added->add_xact(new xact_t(acct)); } else if (i == end) { // If no argument were given but the payee, assume the user wants - // to see the same transaction as last time. + // to see the same xact as last time. added->code = matching->code; - for (transactions_list::iterator k = matching->transactions.begin(); - k != matching->transactions.end(); + for (xacts_list::iterator k = matching->xacts.begin(); + k != matching->xacts.end(); k++) - added->add_transaction(new transaction_t(**k)); + added->add_xact(new xact_t(**k)); } else if ((*i)[0] == '-' || std::isdigit((*i)[0])) { - transaction_t * m_xact, * xact, * first; - m_xact = matching->transactions.front(); + xact_t * m_xact, * xact, * first; + m_xact = matching->xacts.front(); - first = xact = new transaction_t(m_xact->account, amount_t(*i++)); - added->add_transaction(xact); + first = xact = new xact_t(m_xact->account, amount_t(*i++)); + added->add_xact(xact); if (! xact->amount.commodity()) xact->amount.set_commodity(m_xact->amount.commodity()); - m_xact = matching->transactions.back(); + m_xact = matching->xacts.back(); - xact = new transaction_t(m_xact->account, - first->amount); - added->add_transaction(xact); + xact = new xact_t(m_xact->account, - first->amount); + added->add_xact(xact); if (i != end) { account_t * acct = session.find_account_re(*i); if (! acct) acct = session.find_account(*i); assert(acct); - added->transactions.back()->account = acct; + added->xacts.back()->account = acct; } } else { @@ -137,9 +137,9 @@ entry_t * derive_new_entry(report_t& report, for (; j != matching->journal->entries.rend(); j++) if (regexp.match((*j)->payee)) { entry_t * entry = *j; - for (transactions_list::const_iterator x = - entry->transactions.begin(); - x != entry->transactions.end(); + for (xacts_list::const_iterator x = + entry->xacts.begin(); + x != entry->xacts.end(); x++) if (acct_regex.match((*x)->account->fullname())) { acct = (*x)->account; @@ -150,12 +150,12 @@ entry_t * derive_new_entry(report_t& report, } found: - transaction_t * xact; + xact_t * xact; if (i == end) { if (amt) - xact = new transaction_t(acct, *amt); + xact = new xact_t(acct, *amt); else - xact = new transaction_t(acct); + xact = new xact_t(acct); } else { amount_t amount(*i++); @@ -172,7 +172,7 @@ entry_t * derive_new_entry(report_t& report, if (! acct) acct = session.find_account(re_pat); - xact = new transaction_t(acct, amount); + xact = new xact_t(acct, amount); if (! xact->amount.commodity()) { if (amt) xact->amount.set_commodity(amt->commodity()); @@ -180,22 +180,22 @@ entry_t * derive_new_entry(report_t& report, xact->amount.set_commodity(*amount_t::current_pool->default_commodity); } } - added->add_transaction(xact); + added->add_xact(xact); } if (! draw_acct) { - assert(matching->transactions.back()->account); - draw_acct = matching->transactions.back()->account; + assert(matching->xacts.back()->account); + draw_acct = matching->xacts.back()->account; } if (draw_acct) - added->add_transaction(new transaction_t(draw_acct)); + added->add_xact(new xact_t(draw_acct)); } if ((matching && - ! run_hooks(matching->journal->entry_finalize_hooks, *added, false)) || + ! matching->journal->entry_finalize_hooks.run_hooks(*added, false)) || ! added->finalize() || (matching && - ! run_hooks(matching->journal->entry_finalize_hooks, *added, true))) + ! matching->journal->entry_finalize_hooks.run_hooks(*added, true))) throw new error("Failed to finalize derived entry (check commodities)"); return added.release(); diff --git a/emacs.cc b/emacs.cc index 44b372fe..a398b9c4 100644 --- a/emacs.cc +++ b/emacs.cc @@ -2,7 +2,7 @@ namespace ledger { -void format_emacs_transactions::write_entry(entry_t& entry) +void format_emacs_xacts::write_entry(entry_t& entry) { int idx = entry.src_idx; for (paths_list::const_iterator i = entry.journal->sources.begin(); @@ -33,10 +33,10 @@ void format_emacs_transactions::write_entry(entry_t& entry) out << "\n"; } -void format_emacs_transactions::operator()(transaction_t& xact) +void format_emacs_xacts::operator()(xact_t& xact) { - if (! transaction_has_xdata(xact) || - ! (transaction_xdata_(xact).dflags & TRANSACTION_DISPLAYED)) { + if (! xact_has_xdata(xact) || + ! (xact_xdata_(xact).dflags & XACT_DISPLAYED)) { if (! last_entry) { out << "(("; write_entry(*xact.entry); @@ -54,10 +54,10 @@ void format_emacs_transactions::operator()(transaction_t& xact) << xact.amount << "\""; switch (xact.state) { - case transaction_t::CLEARED: + case xact_t::CLEARED: out << " t"; break; - case transaction_t::PENDING: + case xact_t::PENDING: out << " pending"; break; default: @@ -73,7 +73,7 @@ void format_emacs_transactions::operator()(transaction_t& xact) last_entry = xact.entry; - transaction_xdata(xact).dflags |= TRANSACTION_DISPLAYED; + xact_xdata(xact).dflags |= XACT_DISPLAYED; } } diff --git a/emacs.h b/emacs.h index 1a362cb2..62815220 100644 --- a/emacs.h +++ b/emacs.h @@ -6,21 +6,21 @@ namespace ledger { -class format_emacs_transactions : public item_handler +class format_emacs_xacts : public item_handler { - format_emacs_transactions(); + format_emacs_xacts(); protected: std::ostream& out; entry_t * last_entry; public: - format_emacs_transactions(std::ostream& _out) + format_emacs_xacts(std::ostream& _out) : out(_out), last_entry(NULL) { - TRACE_CTOR(format_emacs_transactions, "std::ostream&"); + TRACE_CTOR(format_emacs_xacts, "std::ostream&"); } - ~format_emacs_transactions() { - TRACE_DTOR(format_emacs_transactions); + ~format_emacs_xacts() { + TRACE_DTOR(format_emacs_xacts); } virtual void write_entry(entry_t& entry); @@ -29,7 +29,7 @@ public: out << "))\n"; out.flush(); } - virtual void operator()(transaction_t& xact); + virtual void operator()(xact_t& xact); }; } // namespace ledger diff --git a/entry.cc b/entry.cc new file mode 100644 index 00000000..06e2a131 --- /dev/null +++ b/entry.cc @@ -0,0 +1,451 @@ +/* + * Copyright (c) 2003-2008, 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 + * met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of New Artisans LLC nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "entry.h" +#include "journal.h" +#include "format.h" + +namespace ledger { + +entry_base_t::entry_base_t(const entry_base_t& e) + : journal(NULL), beg_pos(0), beg_line(0), end_pos(0), end_line(0) +{ + TRACE_CTOR(entry_base_t, "copy"); + + for (xacts_list::const_iterator i = e.xacts.begin(); + i != e.xacts.end(); + i++) + xacts.push_back(new xact_t(**i)); +} + +entry_base_t::~entry_base_t() +{ + TRACE_DTOR(entry_base_t); + + for (xacts_list::iterator i = xacts.begin(); + i != xacts.end(); + i++) + if (! (*i)->has_flags(XACT_BULK_ALLOC)) + checked_delete(*i); + else + (*i)->~xact_t(); +} + +void entry_base_t::add_xact(xact_t * xact) +{ + xacts.push_back(xact); +} + +bool entry_base_t::remove_xact(xact_t * xact) +{ + xacts.remove(xact); + return true; +} + +bool entry_base_t::finalize() +{ + // Scan through and compute the total balance for the entry. This is used + // for auto-calculating the value of entries with no cost, and the per-unit + // price of unpriced commodities. + + // (let ((balance 0) + // null-xact) + + value_t balance; + xact_t * null_xact = NULL; + + // (do-xacts (xact entry) + // (when (xact-must-balance-p xact) + // (let ((amt (xact-amount* xact))) + // (if amt + // (setf balance (add balance (or (xact-cost xact) amt))) + // (if null-xact + // (error "Only one xact with null amount allowed ~ + // per entry (beg ~S end ~S)" + // (item-position-begin-line (entry-position entry)) + // (item-position-end-line (entry-position entry))) + // (setf null-xact xact)))))) + // + + for (xacts_list::const_iterator x = xacts.begin(); + x != xacts.end(); + x++) { + if ((*x)->must_balance()) { + amount_t& p((*x)->cost ? *(*x)->cost : (*x)->amount); + if (! p.is_null()) { + if (balance.is_null()) + balance = p; + else + balance += p; + } else { + if (null_xact) + throw_(std::logic_error, + "Only one xact with null amount allowed per entry"); + else + null_xact = *x; + } + } + } + assert(balance.valid()); + + DEBUG("ledger.journal.finalize", "initial balance = " << balance); + + // If there is only one xact, balance against the default account if + // one has been set. + + // (when (= 1 (length (entry-xacts entry))) + // (if-let ((default-account + // (journal-default-account (entry-journal entry)))) + // (setf null-xact + // (make-xact :entry entry + // :status (xact-status + // (first (entry-xacts entry))) + // :account default-account + // :generatedp t)) + // (add-xact entry null-xact))) + + if (journal && journal->basket && xacts.size() == 1) { + // jww (2008-07-24): Need to make the rest of the code aware of what to do + // when it sees a generated xact. + null_xact = new xact_t(journal->basket, XACT_GENERATED); + null_xact->state = (*xacts.begin())->state; + add_xact(null_xact); + } + + if (null_xact != NULL) { + // If one xact has no value at all, its value will become the + // inverse of the rest. If multiple commodities are involved, multiple + // xacts are generated to balance them all. + + // (progn + // (if (balance-p balance) + // (let ((first t)) + // (dolist (amount (balance-amounts balance)) + // (if first + // (setf (xact-amount* null-xact) (negate amount) + // first nil) + // (add-xact + // entry + // (make-xact :entry entry + // :account (xact-account null-xact) + // :amount (negate amount) + // :generatedp t))))) + // (setf (xact-amount* null-xact) (negate balance) + // (xact-calculatedp null-xact) t)) + // + // (setf balance 0)) + + if (balance.is_balance()) { + bool first = true; + const balance_t& bal(balance.as_balance()); + for (balance_t::amounts_map::const_iterator i = bal.amounts.begin(); + i != bal.amounts.end(); + i++) { + if (first) { + null_xact->amount = (*i).second.negate(); + first = false; + } else { + add_xact(new xact_t(null_xact->account, + (*i).second.negate(), + XACT_GENERATED)); + } + } + } else { + null_xact->amount = balance.as_amount().negate(); + null_xact->add_flags(XACT_CALCULATED); + } + balance = NULL_VALUE; + + } + else if (balance.is_balance() && + balance.as_balance().amounts.size() == 2) { + // When an entry involves two different commodities (regardless of how + // many xacts there are) determine the conversion ratio by dividing + // the total value of one commodity by the total value of the other. This + // establishes the per-unit cost for this xact for both + // commodities. + + // (when (and (balance-p balance) + // (= 2 (balance-commodity-count balance))) + // (destructuring-bind (x y) (balance-amounts balance) + // (let ((a-commodity (amount-commodity x)) + // (per-unit-cost (value-abs (divide x y)))) + // (do-xacts (xact entry) + // (let ((amount (xact-amount* xact))) + // (unless (or (xact-cost xact) + // (not (xact-must-balance-p xact)) + // (commodity-equal (amount-commodity amount) + // a-commodity)) + // (setf balance (subtract balance amount) + // (xact-cost xact) (multiply per-unit-cost amount) + // balance (add balance (xact-cost xact)))))))))) + + const balance_t& bal(balance.as_balance()); + + balance_t::amounts_map::const_iterator a = bal.amounts.begin(); + + const amount_t& x((*a++).second); + const amount_t& y((*a++).second); + + if (! y.is_realzero()) { + amount_t per_unit_cost = (x / y).abs(); + + commodity_t& comm(x.commodity()); + + for (xacts_list::const_iterator x = xacts.begin(); + x != xacts.end(); + x++) { + const amount_t& x_amt((*x)->amount); + + if (! ((*x)->cost || + ! (*x)->must_balance() || + x_amt.commodity() == comm)) { + DEBUG("ledger.journal.finalize", "before operation 1 = " << balance); + balance -= x_amt; + DEBUG("ledger.journal.finalize", "after operation 1 = " << balance); + DEBUG("ledger.journal.finalize", "x_amt = " << x_amt); + DEBUG("ledger.journal.finalize", "per_unit_cost = " << per_unit_cost); + + (*x)->cost = per_unit_cost * x_amt; + DEBUG("ledger.journal.finalize", "*(*x)->cost = " << *(*x)->cost); + + balance += *(*x)->cost; + DEBUG("ledger.journal.finalize", "after operation 2 = " << balance); + } + + } + } + + DEBUG("ledger.journal.finalize", "resolved balance = " << balance); + } + + // Now that the xact list has its final form, calculate the balance + // once more in terms of total cost, accounting for any possible gain/loss + // amounts. + + // (do-xacts (xact entry) + // (when (xact-cost xact) + // (let ((amount (xact-amount* xact))) + // (assert (not (commodity-equal (amount-commodity amount) + // (amount-commodity (xact-cost xact))))) + // (multiple-value-bind (annotated-amount total-cost basis-cost) + // (exchange-commodity amount :total-cost (xact-cost xact) + // :moment (entry-date entry) + // :tag (entry-code entry)) + // (if (annotated-commodity-p (amount-commodity amount)) + // (if-let ((price (annotation-price + // (commodity-annotation + // (amount-commodity amount))))) + // (setf balance + // (add balance (subtract basis-cost total-cost)))) + // (setf (xact-amount* xact) annotated-amount)))))) + + for (xacts_list::const_iterator x = xacts.begin(); + x != xacts.end(); + x++) { + if ((*x)->cost) { + const amount_t& x_amt((*x)->amount); + + assert(x_amt.commodity() != (*x)->cost->commodity()); + + entry_t * entry = dynamic_cast(this); + + // jww (2008-07-24): Pass the entry's code here if we can, as the + // auto-tag + amount_t final_cost; + amount_t basis_cost; + amount_t ann_amount = + commodity_t::exchange(x_amt, final_cost, basis_cost, + (*x)->cost, none, (*x)->actual_date(), + entry ? entry->code : optional()); + + if ((*x)->amount.commodity_annotated()) { + if (ann_amount.annotation_details().price) { + if (balance.is_null()) + balance = basis_cost - final_cost; + else + balance += basis_cost - final_cost; + } + } else { + (*x)->amount = ann_amount; + } + } + } + + DEBUG("ledger.journal.finalize", "final balance = " << balance); + + // (if (value-zerop balance) + // (prog1 + // entry + // (setf (entry-normalizedp entry) t)) + // (error "Entry does not balance (beg ~S end ~S); remaining balance is:~%~A" + // (item-position-begin-line (entry-position entry)) + // (item-position-end-line (entry-position entry)) + // (format-value balance :width 20))) + + if (! balance.is_null() && ! balance.is_zero()) { + error * err = + new balance_error("Entry does not balance", + new entry_context(*this, "While balancing entry:")); + balance.round(); + err->context.push_front + (new value_context(balance, "Unbalanced remainder is:")); + throw err; + } + + return true; +} + +entry_t::entry_t(const entry_t& e) + : entry_base_t(e), _date(e._date), _date_eff(e._date_eff), + code(e.code), payee(e.payee) +{ + TRACE_CTOR(entry_t, "copy"); + + for (xacts_list::const_iterator i = xacts.begin(); + i != xacts.end(); + i++) + (*i)->entry = this; +} + +bool entry_t::get_state(xact_t::state_t * state) const +{ + bool first = true; + bool hetero = false; + + for (xacts_list::const_iterator i = xacts.begin(); + i != xacts.end(); + i++) { + if (first) { + *state = (*i)->state; + first = false; + } + else if (*state != (*i)->state) { + hetero = true; + break; + } + } + + return ! hetero; +} + +void entry_t::add_xact(xact_t * xact) +{ + xact->entry = this; + entry_base_t::add_xact(xact); +} + +bool entry_t::valid() const +{ + if (! is_valid(_date) || ! journal) { + DEBUG("ledger.validate", "entry_t: ! _date || ! journal"); + return false; + } + + for (xacts_list::const_iterator i = xacts.begin(); + i != xacts.end(); + i++) + if ((*i)->entry != this || ! (*i)->valid()) { + DEBUG("ledger.validate", "entry_t: xact not valid"); + return false; + } + + return true; +} + +void entry_context::describe(std::ostream& out) const throw() +{ + if (! desc.empty()) + out << desc << std::endl; + + print_entry(out, entry, " "); +} + +void auto_entry_t::extend_entry(entry_base_t& entry, bool post) +{ + xacts_list initial_xacts(entry.xacts.begin(), + entry.xacts.end()); + + for (xacts_list::iterator i = initial_xacts.begin(); + i != initial_xacts.end(); + i++) { + if (predicate(**i)) { + for (xacts_list::iterator t = xacts.begin(); + t != xacts.end(); + t++) { + amount_t amt; + assert((*t)->amount); + if (! (*t)->amount.commodity()) { + if (! post) + continue; + assert((*i)->amount); + amt = (*i)->amount * (*t)->amount; + } else { + if (post) + continue; + amt = (*t)->amount; + } + + account_t * account = (*t)->account; + string fullname = account->fullname(); + assert(! fullname.empty()); + if (fullname == "$account" || fullname == "@account") + account = (*i)->account; + + xact_t * xact + = new xact_t(account, amt, (*t)->flags() | XACT_AUTO); + + // Copy over details so that the resulting xact is a mirror of + // the automated entry's one. + xact->state = (*t)->state; + xact->_date = (*t)->_date; + xact->_date_eff = (*t)->_date_eff; + xact->note = (*t)->note; + xact->beg_pos = (*t)->beg_pos; + xact->beg_line = (*t)->beg_line; + xact->end_pos = (*t)->end_pos; + xact->end_line = (*t)->end_line; + + entry.add_xact(xact); + } + } + } +} + +void extend_entry_base(journal_t * journal, entry_base_t& entry, bool post) +{ + for (auto_entries_list::iterator i = journal->auto_entries.begin(); + i != journal->auto_entries.end(); + i++) + (*i)->extend_entry(entry, post); +} + +} // namespace ledger diff --git a/entry.h b/entry.h new file mode 100644 index 00000000..860fc7a5 --- /dev/null +++ b/entry.h @@ -0,0 +1,249 @@ +/* + * Copyright (c) 2003-2008, 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 + * met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of New Artisans LLC nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _ENTRY_H +#define _ENTRY_H + +#include "xact.h" +#include "predicate.h" + +namespace ledger { + +class journal_t; + +typedef std::list xacts_list; + +class entry_base_t +{ + public: + journal_t * journal; + string note; + unsigned long src_idx; + istream_pos_type beg_pos; + unsigned long beg_line; + istream_pos_type end_pos; + unsigned long end_line; + xacts_list xacts; + + entry_base_t() : journal(NULL), + beg_pos(0), beg_line(0), end_pos(0), end_line(0) + { + TRACE_CTOR(entry_base_t, ""); + } + entry_base_t(const entry_base_t& e); + + virtual ~entry_base_t(); + + bool operator==(const entry_base_t& entry) { + return this == &entry; + } + bool operator!=(const entry_base_t& entry) { + return ! (*this == entry); + } + + virtual void add_xact(xact_t * xact); + virtual bool remove_xact(xact_t * xact); + + virtual bool finalize(); + virtual bool valid() const = 0; +}; + +class entry_t : public entry_base_t +{ +public: + datetime_t _date; + optional _date_eff; + optional code; + string payee; + + entry_t() { + TRACE_CTOR(entry_t, ""); + } + entry_t(const entry_t& e); + + virtual ~entry_t() { + TRACE_DTOR(entry_t); + } + + datetime_t actual_date() const { + return _date; + } + datetime_t effective_date() const { + if (! _date_eff) + return _date; + return *_date_eff; + } + datetime_t date() const { + if (xact_t::use_effective_date) + return effective_date(); + else + return actual_date(); + } + + virtual void add_xact(xact_t * xact); + + virtual bool valid() const; + + bool get_state(xact_t::state_t * state) const; +}; + +struct entry_finalizer_t { + virtual ~entry_finalizer_t() {} + virtual bool operator()(entry_t& entry, bool post) = 0; +}; + +class entry_context : public error_context { + public: + const entry_base_t& entry; + + entry_context(const entry_base_t& _entry, + const string& _desc = "") throw() + : error_context(_desc), entry(_entry) {} + virtual ~entry_context() throw() {} + + virtual void describe(std::ostream& out) const throw(); +}; + +class auto_entry_t : public entry_base_t +{ +public: + item_predicate predicate; + + auto_entry_t() { + TRACE_CTOR(auto_entry_t, ""); + } + auto_entry_t(const auto_entry_t& other) + : predicate(other.predicate) { + TRACE_CTOR(auto_entry_t, "copy"); + } + auto_entry_t(const string& _predicate) + : predicate(_predicate) + { + TRACE_CTOR(auto_entry_t, "const string&"); + } + + virtual ~auto_entry_t() { + TRACE_DTOR(auto_entry_t); + } + + virtual void extend_entry(entry_base_t& entry, bool post); + virtual bool valid() const { + return true; + } +}; + +struct auto_entry_finalizer_t : public entry_finalizer_t +{ + journal_t * journal; + + auto_entry_finalizer_t() : journal(NULL) { + TRACE_CTOR(auto_entry_finalizer_t, ""); + } + auto_entry_finalizer_t(const auto_entry_finalizer_t& other) + : journal(other.journal) { + TRACE_CTOR(auto_entry_finalizer_t, "copy"); + } + auto_entry_finalizer_t(journal_t * _journal) : journal(_journal) { + TRACE_CTOR(auto_entry_finalizer_t, "journal_t *"); + } + ~auto_entry_finalizer_t() throw() { + TRACE_DTOR(auto_entry_finalizer_t); + } + + virtual bool operator()(entry_t& entry, bool post); +}; + +class period_entry_t : public entry_base_t +{ + public: + interval_t period; + string period_string; + + period_entry_t() { + TRACE_CTOR(period_entry_t, ""); + } + period_entry_t(const period_entry_t& e) + : entry_base_t(e), period(e.period), period_string(e.period_string) { + TRACE_CTOR(period_entry_t, "copy"); + } + period_entry_t(const string& _period) + : period(_period), period_string(_period) { + TRACE_CTOR(period_entry_t, "const string&"); + } + + virtual ~period_entry_t() throw() { + TRACE_DTOR(period_entry_t); + } + + virtual bool valid() const { + return period; + } +}; + +class func_finalizer_t : public entry_finalizer_t +{ + func_finalizer_t(); + +public: + typedef function func_t; + + func_t func; + + func_finalizer_t(func_t _func) : func(_func) { + TRACE_CTOR(func_finalizer_t, "func_t"); + } + func_finalizer_t(const func_finalizer_t& other) : + entry_finalizer_t(), func(other.func) { + TRACE_CTOR(func_finalizer_t, "copy"); + } + ~func_finalizer_t() throw() { + TRACE_DTOR(func_finalizer_t); + } + + virtual bool operator()(entry_t& entry, bool post) { + return func(entry, post); + } +}; + +typedef std::list entries_list; +typedef std::list auto_entries_list; +typedef std::list period_entries_list; + +void extend_entry_base(journal_t * journal, entry_base_t& entry, bool post); + +inline bool auto_entry_finalizer_t::operator()(entry_t& entry, bool post) { + extend_entry_base(journal, entry, post); + return true; +} + +} // namespace ledger + +#endif // _ENTRY_H diff --git a/expr.cc b/expr.cc index 0319e243..086f2494 100644 --- a/expr.cc +++ b/expr.cc @@ -111,6 +111,23 @@ value_t expr_t::calc(scope_t& scope) const return NULL_VALUE; } +bool expr_t::is_constant() const +{ + return ptr.get() && ptr->is_value(); +} + +value_t& expr_t::constant_value() +{ + assert(is_constant()); + return ptr->as_value_lval(); +} + +const value_t& expr_t::constant_value() const +{ + assert(is_constant()); + return ptr->as_value(); +} + value_t expr_t::eval(const string& _expr, scope_t& scope) { return expr_t(_expr).calc(scope); diff --git a/expr.h b/expr.h index 4e415496..c81a24df 100644 --- a/expr.h +++ b/expr.h @@ -93,18 +93,22 @@ public: str = txt; } - void parse(const string& _str, const unsigned int flags = 0); - void parse(std::istream& in, const unsigned int flags = 0); - - void compile(scope_t& scope); - value_t calc(scope_t& scope) const; - - void print(std::ostream& out, scope_t& scope) const; - void dump(std::ostream& out) const; - - void read(std::ostream& in); - void read(const char *& data); - void write(std::ostream& out) const; + void parse(const string& _str, const unsigned int flags = 0); + void parse(std::istream& in, const unsigned int flags = 0); + + void compile(scope_t& scope); + value_t calc(scope_t& scope) const; + + bool is_constant() const; + value_t& constant_value(); + const value_t& constant_value() const; + + void print(std::ostream& out, scope_t& scope) const; + void dump(std::ostream& out) const; + + void read(std::ostream& in); + void read(const char *& data); + void write(std::ostream& out) const; static value_t eval(const string& _expr, scope_t& scope); }; diff --git a/format.cc b/format.cc index 4615afa0..cf37a9a2 100644 --- a/format.cc +++ b/format.cc @@ -487,15 +487,15 @@ void format_t::format(std::ostream& out_str, const scope_t& scope) const } else if (details.entry) { unsigned int xacts_count = 0; - transaction_t * first = NULL; - transaction_t * last = NULL; + xact_t * first = NULL; + xact_t * last = NULL; - for (transactions_list::const_iterator i - = details.entry->transactions.begin(); - i != details.entry->transactions.end(); + for (xacts_list::const_iterator i + = details.entry->xacts.begin(); + i != details.entry->xacts.end(); i++) - if (transaction_has_xdata(**i) && - transaction_xdata_(**i).dflags & TRANSACTION_TO_DISPLAY) { + if (xact_has_xdata(**i) && + xact_xdata_(**i).dflags & XACT_TO_DISPLAY) { xacts_count++; if (! first) first = *i; @@ -631,13 +631,13 @@ void format_t::format(std::ostream& out_str, const scope_t& scope) const case element_t::CLEARED: if (details.xact) { switch (details.xact->state) { - case transaction_t::CLEARED: + case xact_t::CLEARED: out << "* "; break; - case transaction_t::PENDING: + case xact_t::PENDING: out << "! "; break; - case transaction_t::UNCLEARED: + case xact_t::UNCLEARED: break; } } @@ -645,16 +645,16 @@ void format_t::format(std::ostream& out_str, const scope_t& scope) const case element_t::ENTRY_CLEARED: if (details.entry) { - transaction_t::state_t state; + xact_t::state_t state; if (details.entry->get_state(&state)) switch (state) { - case transaction_t::CLEARED: + case xact_t::CLEARED: out << "* "; break; - case transaction_t::PENDING: + case xact_t::PENDING: out << "! "; break; - case transaction_t::UNCLEARED: + case xact_t::UNCLEARED: break; } } @@ -692,16 +692,16 @@ void format_t::format(std::ostream& out_str, const scope_t& scope) const case element_t::OPT_ACCOUNT: if (details.entry && details.xact) { - transaction_t::state_t state; + xact_t::state_t state; if (! details.entry->get_state(&state)) switch (details.xact->state) { - case transaction_t::CLEARED: + case xact_t::CLEARED: name = "* "; break; - case transaction_t::PENDING: + case xact_t::PENDING: name = "! "; break; - case transaction_t::UNCLEARED: + case xact_t::UNCLEARED: break; } } @@ -714,11 +714,11 @@ void format_t::format(std::ostream& out_str, const scope_t& scope) const details.account->fullname() : partial_account_name(*details.account)); - if (details.xact && details.xact->has_flags(TRANSACTION_VIRTUAL)) { + if (details.xact && details.xact->has_flags(XACT_VIRTUAL)) { if (elem->max_width > 2) name = truncate(name, elem->max_width - 2, true); - if (details.xact->has_flags(TRANSACTION_BALANCE)) + if (details.xact->has_flags(XACT_BALANCE)) name = string("[") + name + "]"; else name = string("(") + name + ")"; @@ -763,11 +763,11 @@ void format_t::format(std::ostream& out_str, const scope_t& scope) const } } -format_transactions::format_transactions(std::ostream& _output_stream, +format_xacts::format_xacts(std::ostream& _output_stream, const string& format) : output_stream(_output_stream), last_entry(NULL), last_xact(NULL) { - TRACE_CTOR(format_transactions, "std::ostream&, const string&"); + TRACE_CTOR(format_xacts, "std::ostream&, const string&"); const char * f = format.c_str(); if (const char * p = std::strstr(f, "%/")) { @@ -779,11 +779,11 @@ format_transactions::format_transactions(std::ostream& _output_stream, } } -void format_transactions::operator()(transaction_t& xact) +void format_xacts::operator()(xact_t& xact) { #if 0 - if (! transaction_has_xdata(xact) || - ! (transaction_xdata_(xact).dflags & TRANSACTION_DISPLAYED)) { + if (! xact_has_xdata(xact) || + ! (xact_xdata_(xact).dflags & XACT_DISPLAYED)) { if (last_entry != xact.entry) { first_line_format.format(output_stream, details_t(xact)); last_entry = xact.entry; @@ -795,7 +795,7 @@ void format_transactions::operator()(transaction_t& xact) next_lines_format.format(output_stream, details_t(xact)); } - transaction_xdata(xact).dflags |= TRANSACTION_DISPLAYED; + xact_xdata(xact).dflags |= XACT_DISPLAYED; last_xact = &xact; } #endif @@ -805,26 +805,26 @@ void format_entries::format_last_entry() { #if 0 bool first = true; - for (transactions_list::const_iterator i = last_entry->transactions.begin(); - i != last_entry->transactions.end(); + for (xacts_list::const_iterator i = last_entry->xacts.begin(); + i != last_entry->xacts.end(); i++) { - if (transaction_has_xdata(**i) && - transaction_xdata_(**i).dflags & TRANSACTION_TO_DISPLAY) { + if (xact_has_xdata(**i) && + xact_xdata_(**i).dflags & XACT_TO_DISPLAY) { if (first) { first_line_format.format(output_stream, details_t(**i)); first = false; } else { next_lines_format.format(output_stream, details_t(**i)); } - transaction_xdata_(**i).dflags |= TRANSACTION_DISPLAYED; + xact_xdata_(**i).dflags |= XACT_DISPLAYED; } } #endif } -void format_entries::operator()(transaction_t& xact) +void format_entries::operator()(xact_t& xact) { - transaction_xdata(xact).dflags |= TRANSACTION_TO_DISPLAY; + xact_xdata(xact).dflags |= XACT_TO_DISPLAY; if (last_entry && xact.entry != last_entry) format_last_entry(); @@ -858,13 +858,11 @@ void print_entry(std::ostream& out, const entry_base_t& entry_base, #if 0 format_entries formatter(out, print_format); - walk_transactions(const_cast(entry_base.transactions), - formatter); + walk_xacts(const_cast(entry_base.xacts), formatter); formatter.flush(); - clear_transaction_xdata cleaner; - walk_transactions(const_cast(entry_base.transactions), - cleaner); + clear_xact_xdata cleaner; + walk_xacts(const_cast(entry_base.xacts), cleaner); #endif } diff --git a/format.h b/format.h index eb735180..e28b6964 100644 --- a/format.h +++ b/format.h @@ -113,33 +113,33 @@ struct format_t : public noncopyable void format(std::ostream& out, const scope_t& scope) const; }; -class format_transactions : public item_handler +class format_xacts : public item_handler { protected: std::ostream& output_stream; format_t first_line_format; format_t next_lines_format; entry_t * last_entry; - transaction_t * last_xact; + xact_t * last_xact; public: - format_transactions(std::ostream& _output_stream, + format_xacts(std::ostream& _output_stream, const string& format); - ~format_transactions() throw() { - TRACE_DTOR(format_transactions); + ~format_xacts() throw() { + TRACE_DTOR(format_xacts); } virtual void flush() { output_stream.flush(); } - virtual void operator()(transaction_t& xact); + virtual void operator()(xact_t& xact); }; -class format_entries : public format_transactions +class format_entries : public format_xacts { public: format_entries(std::ostream& output_stream, const string& format) - : format_transactions(output_stream, format) { + : format_xacts(output_stream, format) { TRACE_CTOR(format_entries, "std::ostream&, const string&"); } ~format_entries() throw() { @@ -153,9 +153,9 @@ class format_entries : public format_transactions format_last_entry(); last_entry = NULL; } - format_transactions::flush(); + format_xacts::flush(); } - virtual void operator()(transaction_t& xact); + virtual void operator()(xact_t& xact); }; void print_entry(std::ostream& out, const entry_base_t& entry, diff --git a/gnucash.cc b/gnucash.cc index 5e5ae1f8..59902da2 100644 --- a/gnucash.cc +++ b/gnucash.cc @@ -49,7 +49,7 @@ static unsigned int src_idx; static istream_pos_type beg_pos; static unsigned long beg_line; -static transaction_t::state_t curr_state; +static xact_t::state_t curr_state; static enum action_t { NO_ACTION, @@ -90,7 +90,7 @@ static void startElement(void *userData, const char *name, const char **atts) action = COMM_NAME; else if (std::strcmp(name, "cmdty:fraction") == 0) action = COMM_PREC; - else if (std::strcmp(name, "gnc:transaction") == 0) { + else if (std::strcmp(name, "gnc:xact") == 0) { assert(! curr_entry); curr_entry = new entry_t; } @@ -104,7 +104,7 @@ static void startElement(void *userData, const char *name, const char **atts) action = ENTRY_DESC; else if (std::strcmp(name, "trn:split") == 0) { assert(curr_entry); - curr_entry->add_transaction(new transaction_t(curr_account)); + curr_entry->add_xact(new xact_t(curr_account)); } else if (std::strcmp(name, "split:reconciled-state") == 0) action = XACT_STATE; @@ -132,10 +132,10 @@ static void endElement(void *userData, const char *name) else if (std::strcmp(name, "gnc:commodity") == 0) { curr_comm = NULL; } - else if (std::strcmp(name, "gnc:transaction") == 0) { + else if (std::strcmp(name, "gnc:xact") == 0) { assert(curr_entry); - // Add the new entry (what gnucash calls a 'transaction') to the + // Add the new entry (what gnucash calls a 'xact') to the // journal if (! curr_journal->add_entry(curr_entry)) { print_entry(std::cerr, *curr_entry); @@ -155,11 +155,11 @@ static void endElement(void *userData, const char *name) entry_comm = NULL; } else if (std::strcmp(name, "trn:split") == 0) { - transaction_t * xact = curr_entry->transactions.back(); + xact_t * xact = curr_entry->xacts.back(); // Identify the commodity to use for the value of this - // transaction. The quantity indicates how many times that value - // the transaction is worth. + // xact. The quantity indicates how many times that value + // the xact is worth. amount_t value; commodity_t * default_commodity = NULL; account_comm_map::iterator ac = account_comms.find(xact->account); @@ -187,7 +187,7 @@ static void endElement(void *userData, const char *name) xact->end_line = XML_GetCurrentLineNumber(parser) - offset; // Clear the relevant variables for the next run - curr_state = transaction_t::UNCLEARED; + curr_state = xact_t::UNCLEARED; curr_value = amount_t(); curr_quant = amount_t(); } @@ -281,11 +281,11 @@ static void dataHandler(void *userData, const char *s, int len) case XACT_STATE: if (*s == 'y') - curr_state = transaction_t::CLEARED; + curr_state = xact_t::CLEARED; else if (*s == 'n') - curr_state = transaction_t::UNCLEARED; + curr_state = xact_t::UNCLEARED; else - curr_state = transaction_t::PENDING; + curr_state = xact_t::PENDING; break; case XACT_VALUE: { @@ -304,7 +304,7 @@ static void dataHandler(void *userData, const char *s, int len) break; case XACT_ACCOUNT: { - transaction_t * xact = curr_entry->transactions.back(); + xact_t * xact = curr_entry->xacts.back(); accounts_map::iterator i = accounts_by_id.find(string(s, len)); if (i != accounts_by_id.end()) { @@ -319,7 +319,7 @@ static void dataHandler(void *userData, const char *s, int len) } case XACT_NOTE: - curr_entry->transactions.back()->note = string(s, len); + curr_entry->xacts.back()->note = string(s, len); break; case NO_ACTION: @@ -366,7 +366,7 @@ unsigned int gnucash_parser_t::parse(std::istream& in, curr_entry = NULL; curr_comm = NULL; entry_comm = NULL; - curr_state = transaction_t::UNCLEARED; + curr_state = xact_t::UNCLEARED; instreamp = ∈ pathname = original_file ? *original_file : ""; diff --git a/hooks.h b/hooks.h new file mode 100644 index 00000000..f9453be9 --- /dev/null +++ b/hooks.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2003-2008, 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 + * met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of New Artisans LLC nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _HOOKS_H +#define _HOOKS_H + +template +class hooks_t : public boost::noncopyable +{ + std::list list; + +public: + hooks_t() { + TRACE_CTOR(hooks_t, ""); + } + ~hooks_t() throw() { + TRACE_DTOR(hooks_t); + } + + void add_hook(T obj, const bool prepend = false) { + if (prepend) + list.push_front(obj); + else + list.push_back(obj); + } + + void remove_hook(T obj) { + list.remove(obj); + } + + template + bool run_hooks(Data& item, bool post) { + for (typename std::list::const_iterator i = list.begin(); + i != list.end(); + i++) + if (! (*(*i))(item, post)) + return false; + return true; + } +}; + +#endif // _HOOKS_H diff --git a/journal.cc b/journal.cc index ff6dbd9b..9b8d47b4 100644 --- a/journal.cc +++ b/journal.cc @@ -30,557 +30,12 @@ */ #include "journal.h" -#include "format.h" #include "session.h" namespace ledger { const string version = PACKAGE_VERSION; -bool transaction_t::use_effective_date = false; - -transaction_t::~transaction_t() -{ - TRACE_DTOR(transaction_t); -} - -datetime_t transaction_t::actual_date() const -{ - if (! _date && entry) - return entry->actual_date(); - return *_date; -} - -datetime_t transaction_t::effective_date() const -{ - if (! _date_eff && entry) - return entry->effective_date(); - return *_date_eff; -} - -bool transaction_t::valid() const -{ - if (! entry) { - DEBUG("ledger.validate", "transaction_t: ! entry"); - return false; - } - - if (state != UNCLEARED && state != CLEARED && state != PENDING) { - DEBUG("ledger.validate", "transaction_t: state is bad"); - return false; - } - - transactions_list::const_iterator i = - std::find(entry->transactions.begin(), - entry->transactions.end(), this); - if (i == entry->transactions.end()) { - DEBUG("ledger.validate", "transaction_t: ! found"); - return false; - } - - if (! account) { - DEBUG("ledger.validate", "transaction_t: ! account"); - return false; - } - - if (! amount.valid()) { - DEBUG("ledger.validate", "transaction_t: ! amount.valid()"); - return false; - } - - if (cost && ! cost->valid()) { - DEBUG("ledger.validate", "transaction_t: cost && ! cost->valid()"); - return false; - } - - if (flags() & ~0x003f) { - DEBUG("ledger.validate", "transaction_t: flags are bad"); - return false; - } - - return true; -} - -void entry_base_t::add_transaction(transaction_t * xact) -{ - transactions.push_back(xact); -} - -bool entry_base_t::remove_transaction(transaction_t * xact) -{ - transactions.remove(xact); - return true; -} - -// jww (2008-04-20): Migrate the Common Lisp version here! - -bool entry_base_t::finalize() -{ - // Scan through and compute the total balance for the entry. This is used - // for auto-calculating the value of entries with no cost, and the per-unit - // price of unpriced commodities. - - // (let ((balance 0) - // null-xact) - - value_t balance; - transaction_t * null_xact = NULL; - - // (do-transactions (xact entry) - // (when (xact-must-balance-p xact) - // (let ((amt (xact-amount* xact))) - // (if amt - // (setf balance (add balance (or (xact-cost xact) amt))) - // (if null-xact - // (error "Only one transaction with null amount allowed ~ - // per entry (beg ~S end ~S)" - // (item-position-begin-line (entry-position entry)) - // (item-position-end-line (entry-position entry))) - // (setf null-xact xact)))))) - // - - for (transactions_list::const_iterator x = transactions.begin(); - x != transactions.end(); - x++) { - if ((*x)->must_balance()) { - amount_t& p((*x)->cost ? *(*x)->cost : (*x)->amount); - if (! p.is_null()) { - if (balance.is_null()) - balance = p; - else - balance += p; - } else { - if (null_xact) - throw_(std::logic_error, - "Only one transaction with null amount allowed per entry"); - else - null_xact = *x; - } - } - } - assert(balance.valid()); - - DEBUG("ledger.journal.finalize", "initial balance = " << balance); - - // If there is only one transaction, balance against the default account if - // one has been set. - - // (when (= 1 (length (entry-transactions entry))) - // (if-let ((default-account - // (journal-default-account (entry-journal entry)))) - // (setf null-xact - // (make-transaction :entry entry - // :status (xact-status - // (first (entry-transactions entry))) - // :account default-account - // :generatedp t)) - // (add-transaction entry null-xact))) - - if (journal && journal->basket && transactions.size() == 1) { - // jww (2008-07-24): Need to make the rest of the code aware of what to do - // when it sees a generated transaction. - null_xact = new transaction_t(journal->basket, TRANSACTION_GENERATED); - null_xact->state = (*transactions.begin())->state; - add_transaction(null_xact); - } - - if (null_xact != NULL) { - // If one transaction has no value at all, its value will become the - // inverse of the rest. If multiple commodities are involved, multiple - // transactions are generated to balance them all. - - // (progn - // (if (balance-p balance) - // (let ((first t)) - // (dolist (amount (balance-amounts balance)) - // (if first - // (setf (xact-amount* null-xact) (negate amount) - // first nil) - // (add-transaction - // entry - // (make-transaction :entry entry - // :account (xact-account null-xact) - // :amount (negate amount) - // :generatedp t))))) - // (setf (xact-amount* null-xact) (negate balance) - // (xact-calculatedp null-xact) t)) - // - // (setf balance 0)) - - if (balance.is_balance()) { - bool first = true; - const balance_t& bal(balance.as_balance()); - for (balance_t::amounts_map::const_iterator i = bal.amounts.begin(); - i != bal.amounts.end(); - i++) { - if (first) { - null_xact->amount = (*i).second.negate(); - first = false; - } else { - add_transaction(new transaction_t(null_xact->account, - (*i).second.negate(), - TRANSACTION_GENERATED)); - } - } - } else { - null_xact->amount = balance.as_amount().negate(); - null_xact->add_flags(TRANSACTION_CALCULATED); - } - balance = NULL_VALUE; - - } - else if (balance.is_balance() && - balance.as_balance().amounts.size() == 2) { - // When an entry involves two different commodities (regardless of how - // many transactions there are) determine the conversion ratio by dividing - // the total value of one commodity by the total value of the other. This - // establishes the per-unit cost for this transaction for both - // commodities. - - // (when (and (balance-p balance) - // (= 2 (balance-commodity-count balance))) - // (destructuring-bind (x y) (balance-amounts balance) - // (let ((a-commodity (amount-commodity x)) - // (per-unit-cost (value-abs (divide x y)))) - // (do-transactions (xact entry) - // (let ((amount (xact-amount* xact))) - // (unless (or (xact-cost xact) - // (not (xact-must-balance-p xact)) - // (commodity-equal (amount-commodity amount) - // a-commodity)) - // (setf balance (subtract balance amount) - // (xact-cost xact) (multiply per-unit-cost amount) - // balance (add balance (xact-cost xact)))))))))) - - const balance_t& bal(balance.as_balance()); - - balance_t::amounts_map::const_iterator a = bal.amounts.begin(); - - const amount_t& x((*a++).second); - const amount_t& y((*a++).second); - - if (! y.is_realzero()) { - amount_t per_unit_cost = (x / y).abs(); - - commodity_t& comm(x.commodity()); - - for (transactions_list::const_iterator x = transactions.begin(); - x != transactions.end(); - x++) { - const amount_t& x_amt((*x)->amount); - - if (! ((*x)->cost || - ! (*x)->must_balance() || - x_amt.commodity() == comm)) { - DEBUG("ledger.journal.finalize", "before operation 1 = " << balance); - balance -= x_amt; - DEBUG("ledger.journal.finalize", "after operation 1 = " << balance); - DEBUG("ledger.journal.finalize", "x_amt = " << x_amt); - DEBUG("ledger.journal.finalize", "per_unit_cost = " << per_unit_cost); - - (*x)->cost = per_unit_cost * x_amt; - DEBUG("ledger.journal.finalize", "*(*x)->cost = " << *(*x)->cost); - - balance += *(*x)->cost; - DEBUG("ledger.journal.finalize", "after operation 2 = " << balance); - } - - } - } - - DEBUG("ledger.journal.finalize", "resolved balance = " << balance); - } - - // Now that the transaction list has its final form, calculate the balance - // once more in terms of total cost, accounting for any possible gain/loss - // amounts. - - // (do-transactions (xact entry) - // (when (xact-cost xact) - // (let ((amount (xact-amount* xact))) - // (assert (not (commodity-equal (amount-commodity amount) - // (amount-commodity (xact-cost xact))))) - // (multiple-value-bind (annotated-amount total-cost basis-cost) - // (exchange-commodity amount :total-cost (xact-cost xact) - // :moment (entry-date entry) - // :tag (entry-code entry)) - // (if (annotated-commodity-p (amount-commodity amount)) - // (if-let ((price (annotation-price - // (commodity-annotation - // (amount-commodity amount))))) - // (setf balance - // (add balance (subtract basis-cost total-cost)))) - // (setf (xact-amount* xact) annotated-amount)))))) - - for (transactions_list::const_iterator x = transactions.begin(); - x != transactions.end(); - x++) { - if ((*x)->cost) { - const amount_t& x_amt((*x)->amount); - - assert(x_amt.commodity() != (*x)->cost->commodity()); - - entry_t * entry = dynamic_cast(this); - - // jww (2008-07-24): Pass the entry's code here if we can, as the - // auto-tag - amount_t final_cost; - amount_t basis_cost; - amount_t ann_amount = - commodity_t::exchange(x_amt, final_cost, basis_cost, - (*x)->cost, none, (*x)->actual_date(), - entry ? entry->code : optional()); - - if ((*x)->amount.commodity_annotated()) { - if (ann_amount.annotation_details().price) { - if (balance.is_null()) - balance = basis_cost - final_cost; - else - balance += basis_cost - final_cost; - } - } else { - (*x)->amount = ann_amount; - } - } - } - - DEBUG("ledger.journal.finalize", "final balance = " << balance); - - // (if (value-zerop balance) - // (prog1 - // entry - // (setf (entry-normalizedp entry) t)) - // (error "Entry does not balance (beg ~S end ~S); remaining balance is:~%~A" - // (item-position-begin-line (entry-position entry)) - // (item-position-end-line (entry-position entry)) - // (format-value balance :width 20))) - - if (! balance.is_null() && ! balance.is_zero()) { - error * err = - new balance_error("Entry does not balance", - new entry_context(*this, "While balancing entry:")); - balance.round(); - err->context.push_front - (new value_context(balance, "Unbalanced remainder is:")); - throw err; - } - - return true; -} - -entry_t::entry_t(const entry_t& e) - : entry_base_t(e), _date(e._date), _date_eff(e._date_eff), - code(e.code), payee(e.payee) -{ - TRACE_CTOR(entry_t, "copy"); - - for (transactions_list::const_iterator i = transactions.begin(); - i != transactions.end(); - i++) - (*i)->entry = this; -} - -bool entry_t::get_state(transaction_t::state_t * state) const -{ - bool first = true; - bool hetero = false; - - for (transactions_list::const_iterator i = transactions.begin(); - i != transactions.end(); - i++) { - if (first) { - *state = (*i)->state; - first = false; - } - else if (*state != (*i)->state) { - hetero = true; - break; - } - } - - return ! hetero; -} - -void entry_t::add_transaction(transaction_t * xact) -{ - xact->entry = this; - entry_base_t::add_transaction(xact); -} - -bool entry_t::valid() const -{ - if (! is_valid(_date) || ! journal) { - DEBUG("ledger.validate", "entry_t: ! _date || ! journal"); - return false; - } - - for (transactions_list::const_iterator i = transactions.begin(); - i != transactions.end(); - i++) - if ((*i)->entry != this || ! (*i)->valid()) { - DEBUG("ledger.validate", "entry_t: transaction not valid"); - return false; - } - - return true; -} - -void auto_entry_t::extend_entry(entry_base_t& entry, bool post) -{ - transactions_list initial_xacts(entry.transactions.begin(), - entry.transactions.end()); - - for (transactions_list::iterator i = initial_xacts.begin(); - i != initial_xacts.end(); - i++) { - if (predicate(**i)) { - for (transactions_list::iterator t = transactions.begin(); - t != transactions.end(); - t++) { - amount_t amt; - assert((*t)->amount); - if (! (*t)->amount.commodity()) { - if (! post) - continue; - assert((*i)->amount); - amt = (*i)->amount * (*t)->amount; - } else { - if (post) - continue; - amt = (*t)->amount; - } - - account_t * account = (*t)->account; - string fullname = account->fullname(); - assert(! fullname.empty()); - if (fullname == "$account" || fullname == "@account") - account = (*i)->account; - - transaction_t * xact - = new transaction_t(account, amt, (*t)->flags() | TRANSACTION_AUTO); - - // Copy over details so that the resulting transaction is a mirror of - // the automated entry's one. - xact->state = (*t)->state; - xact->_date = (*t)->_date; - xact->_date_eff = (*t)->_date_eff; - xact->note = (*t)->note; - xact->beg_pos = (*t)->beg_pos; - xact->beg_line = (*t)->beg_line; - xact->end_pos = (*t)->end_pos; - xact->end_line = (*t)->end_line; - - entry.add_transaction(xact); - } - } - } -} - -account_t::~account_t() -{ - TRACE_DTOR(account_t); - - for (accounts_map::iterator i = accounts.begin(); - i != accounts.end(); - i++) - checked_delete((*i).second); -} - -account_t * account_t::find_account(const string& name, - const bool auto_create) -{ - accounts_map::const_iterator i = accounts.find(name); - if (i != accounts.end()) - return (*i).second; - - char buf[256]; - - string::size_type sep = name.find(':'); - assert(sep < 256|| sep == string::npos); - - const char * first, * rest; - if (sep == string::npos) { - first = name.c_str(); - rest = NULL; - } else { - std::strncpy(buf, name.c_str(), sep); - buf[sep] = '\0'; - - first = buf; - rest = name.c_str() + sep + 1; - } - - account_t * account; - - i = accounts.find(first); - if (i == accounts.end()) { - if (! auto_create) - return NULL; - - account = new account_t(this, first); - std::pair result - = accounts.insert(accounts_map::value_type(first, account)); - assert(result.second); - } else { - account = (*i).second; - } - - if (rest) - account = account->find_account(rest, auto_create); - - return account; -} - -string account_t::fullname() const -{ - if (! _fullname.empty()) { - return _fullname; - } else { - const account_t * first = this; - string fullname = name; - - while (first->parent) { - first = first->parent; - if (! first->name.empty()) - fullname = first->name + ":" + fullname; - } - - _fullname = fullname; - - return fullname; - } -} - -std::ostream& operator<<(std::ostream& out, const account_t& account) -{ - out << account.fullname(); - return out; -} - -bool account_t::valid() const -{ - if (depth > 256) { - DEBUG("ledger.validate", "account_t: depth > 256"); - return false; - } - - for (accounts_map::const_iterator i = accounts.begin(); - i != accounts.end(); - i++) { - if (this == (*i).second) { - DEBUG("ledger.validate", "account_t: parent refers to itself!"); - return false; - } - - if (! (*i).second->valid()) { - DEBUG("ledger.validate", "account_t: child not valid"); - return false; - } - } - - return true; -} - journal_t::journal_t(session_t * _owner) : owner(_owner), basket(NULL), item_pool(NULL), item_pool_end(NULL) { @@ -592,7 +47,7 @@ journal_t::~journal_t() { TRACE_DTOR(journal_t); - // Don't bother unhooking each entry's transactions from the + // Don't bother unhooking each entry's xacts from the // accounts they refer to, because all accounts are about to // be deleted. for (entries_list::iterator i = entries.begin(); @@ -655,17 +110,17 @@ bool journal_t::add_entry(entry_t * entry) { entry->journal = this; - if (! run_hooks(entry_finalize_hooks, *entry, false) || + if (! entry_finalize_hooks.run_hooks(*entry, false) || ! entry->finalize() || - ! run_hooks(entry_finalize_hooks, *entry, true)) { + ! entry_finalize_hooks.run_hooks(*entry, true)) { entry->journal = NULL; return false; } entries.push_back(entry); - for (transactions_list::const_iterator i = entry->transactions.begin(); - i != entry->transactions.end(); + for (xacts_list::const_iterator i = entry->xacts.begin(); + i != entry->xacts.end(); i++) if ((*i)->cost) { assert((*i)->amount); @@ -712,28 +167,4 @@ bool journal_t::valid() const return true; } -void entry_context::describe(std::ostream& out) const throw() -{ - if (! desc.empty()) - out << desc << std::endl; - - print_entry(out, entry, " "); -} - -xact_context::xact_context(const ledger::transaction_t& _xact, - const string& desc) throw() - : file_context("", 0, desc), xact(_xact) -{ - const ledger::paths_list& sources(xact.entry->journal->sources); - unsigned int x = 0; - for (ledger::paths_list::const_iterator i = sources.begin(); - i != sources.end(); - i++, x++) - if (x == xact.entry->src_idx) { - file = *i; - break; - } - line = xact.beg_line; -} - } // namespace ledger diff --git a/journal.h b/journal.h index 636616f2..cfb52cbe 100644 --- a/journal.h +++ b/journal.h @@ -32,423 +32,16 @@ #ifndef _JOURNAL_H #define _JOURNAL_H -#include "amount.h" -#include "value.h" -#include "expr.h" -#include "predicate.h" +#include "utils.h" +#include "hooks.h" +#include "entry.h" namespace ledger { -// These flags persist with the object -#define TRANSACTION_NORMAL 0x0000 -#define TRANSACTION_VIRTUAL 0x0001 -#define TRANSACTION_BALANCE 0x0002 -#define TRANSACTION_AUTO 0x0004 -#define TRANSACTION_BULK_ALLOC 0x0008 -#define TRANSACTION_CALCULATED 0x0010 -#define TRANSACTION_GENERATED 0x0020 - -class entry_t; -class account_t; - -class transaction_t : public supports_flags<> -{ - public: - enum state_t { UNCLEARED, CLEARED, PENDING }; - - entry_t * entry; - state_t state; - account_t * account; - optional _date; - optional _date_eff; - amount_t amount; - expr_t amount_expr; - optional cost; - optional cost_expr; - optional note; - istream_pos_type beg_pos; - unsigned long beg_line; - istream_pos_type end_pos; - unsigned long end_line; - - mutable void * data; - static bool use_effective_date; - - transaction_t(account_t * _account = NULL, - flags_t _flags = TRANSACTION_NORMAL) - : supports_flags<>(_flags), entry(NULL), - state(UNCLEARED), account(_account), - beg_pos(0), beg_line(0), end_pos(0), end_line(0), data(NULL) - { - TRACE_CTOR(transaction_t, "account_t *, flags_t"); - } - transaction_t(account_t * _account, - const amount_t& _amount, - flags_t _flags = TRANSACTION_NORMAL, - const optional& _note = none) - : supports_flags<>(_flags), entry(NULL), state(UNCLEARED), - account(_account), amount(_amount), note(_note), - beg_pos(0), beg_line(0), end_pos(0), end_line(0), data(NULL) - { - TRACE_CTOR(transaction_t, - "account_t *, const amount_t&, flags_t, const string&"); - } - transaction_t(const transaction_t& xact) - : supports_flags<>(xact), - entry(xact.entry), - state(xact.state), - account(xact.account), - _date(xact._date), - _date_eff(xact._date_eff), - amount(xact.amount), - cost(xact.cost), - note(xact.note), - beg_pos(xact.beg_pos), - beg_line(xact.beg_line), - end_pos(xact.end_pos), - end_line(xact.end_line), - data(xact.data) // jww (2008-07-19): What are the copy semantics? - { - TRACE_CTOR(transaction_t, "copy"); - } - ~transaction_t(); - - datetime_t actual_date() const; - datetime_t effective_date() const; - datetime_t date() const { - if (use_effective_date) - return effective_date(); - else - return actual_date(); - } - - bool must_balance() const { - return ! has_flags(TRANSACTION_VIRTUAL) || has_flags(TRANSACTION_BALANCE); - } - - bool valid() const; -}; - -class xact_context : public file_context { - public: - const transaction_t& xact; - - xact_context(const transaction_t& _xact, - const string& desc = "") throw(); - virtual ~xact_context() throw() {} -}; - -class journal_t; - -typedef std::list transactions_list; - -class entry_base_t -{ - public: - journal_t * journal; - string note; - unsigned long src_idx; - istream_pos_type beg_pos; - unsigned long beg_line; - istream_pos_type end_pos; - unsigned long end_line; - transactions_list transactions; - - entry_base_t() : journal(NULL), - beg_pos(0), beg_line(0), end_pos(0), end_line(0) - { - TRACE_CTOR(entry_base_t, ""); - } - entry_base_t(const entry_base_t& e) : journal(NULL), - beg_pos(0), beg_line(0), end_pos(0), end_line(0) - { - TRACE_CTOR(entry_base_t, "copy"); - for (transactions_list::const_iterator i = e.transactions.begin(); - i != e.transactions.end(); - i++) - transactions.push_back(new transaction_t(**i)); - } - - virtual ~entry_base_t() { - TRACE_DTOR(entry_base_t); - - for (transactions_list::iterator i = transactions.begin(); - i != transactions.end(); - i++) - if (! (*i)->has_flags(TRANSACTION_BULK_ALLOC)) - checked_delete(*i); - else - (*i)->~transaction_t(); - } - - bool operator==(const entry_base_t& entry) { - return this == &entry; - } - bool operator!=(const entry_base_t& entry) { - return ! (*this == entry); - } - - virtual void add_transaction(transaction_t * xact); - virtual bool remove_transaction(transaction_t * xact); - - virtual bool finalize(); - virtual bool valid() const = 0; -}; - -class entry_t : public entry_base_t -{ -public: - datetime_t _date; - optional _date_eff; - optional code; - string payee; - - entry_t() { - TRACE_CTOR(entry_t, ""); - } - entry_t(const entry_t& e); - - virtual ~entry_t() { - TRACE_DTOR(entry_t); - } - - datetime_t actual_date() const { - return _date; - } - datetime_t effective_date() const { - if (! _date_eff) - return _date; - return *_date_eff; - } - datetime_t date() const { - if (transaction_t::use_effective_date) - return effective_date(); - else - return actual_date(); - } - - virtual void add_transaction(transaction_t * xact); - - virtual bool valid() const; - - bool get_state(transaction_t::state_t * state) const; -}; - -struct entry_finalizer_t { - virtual ~entry_finalizer_t() {} - virtual bool operator()(entry_t& entry, bool post) = 0; -}; - -class entry_context : public error_context { - public: - const entry_base_t& entry; - - entry_context(const entry_base_t& _entry, - const string& _desc = "") throw() - : error_context(_desc), entry(_entry) {} - virtual ~entry_context() throw() {} - - virtual void describe(std::ostream& out) const throw(); -}; - - -template class item_predicate; - -class auto_entry_t : public entry_base_t -{ -public: - item_predicate predicate; - - auto_entry_t() { - TRACE_CTOR(auto_entry_t, ""); - } - auto_entry_t(const auto_entry_t& other) - : predicate(other.predicate) { - TRACE_CTOR(auto_entry_t, "copy"); - } - auto_entry_t(const string& _predicate) - : predicate(_predicate) - { - TRACE_CTOR(auto_entry_t, "const string&"); - } - - virtual ~auto_entry_t() { - TRACE_DTOR(auto_entry_t); - } - - virtual void extend_entry(entry_base_t& entry, bool post); - virtual bool valid() const { - return true; - } -}; - -struct auto_entry_finalizer_t : public entry_finalizer_t -{ - journal_t * journal; - - auto_entry_finalizer_t() : journal(NULL) { - TRACE_CTOR(auto_entry_finalizer_t, ""); - } - auto_entry_finalizer_t(const auto_entry_finalizer_t& other) - : journal(other.journal) { - TRACE_CTOR(auto_entry_finalizer_t, "copy"); - } - auto_entry_finalizer_t(journal_t * _journal) : journal(_journal) { - TRACE_CTOR(auto_entry_finalizer_t, "journal_t *"); - } - ~auto_entry_finalizer_t() throw() { - TRACE_DTOR(auto_entry_finalizer_t); - } - - virtual bool operator()(entry_t& entry, bool post); -}; - - -class period_entry_t : public entry_base_t -{ - public: - interval_t period; - string period_string; - - period_entry_t() { - TRACE_CTOR(period_entry_t, ""); - } - period_entry_t(const period_entry_t& e) - : entry_base_t(e), period(e.period), period_string(e.period_string) { - TRACE_CTOR(period_entry_t, "copy"); - } - period_entry_t(const string& _period) - : period(_period), period_string(_period) { - TRACE_CTOR(period_entry_t, "const string&"); - } - - virtual ~period_entry_t() throw() { - TRACE_DTOR(period_entry_t); - } - - virtual bool valid() const { - return period; - } -}; - - -typedef std::map accounts_map; - -class account_t -{ - public: - typedef unsigned long ident_t; - - account_t * parent; - string name; - optional note; - unsigned short depth; - accounts_map accounts; - - mutable void * data; - mutable ident_t ident; - mutable string _fullname; - - account_t(account_t * _parent = NULL, - const string& _name = "", - const optional& _note = none) - : parent(_parent), name(_name), note(_note), - depth(parent ? parent->depth + 1 : 0), data(NULL), ident(0) { - TRACE_CTOR(account_t, "account_t *, const string&, const string&"); - } - account_t(const account_t& other) - : parent(other.parent), - name(other.name), - note(other.note), - depth(other.depth), - accounts(other.accounts), - data(NULL), - ident(0) { - TRACE_CTOR(account_t, "copy"); - assert(other.data == NULL); - assert(other.ident == 0); - } - ~account_t(); - - operator string() const { - return fullname(); - } - string fullname() const; - - void add_account(account_t * acct) { - accounts.insert(accounts_map::value_type(acct->name, acct)); - } - bool remove_account(account_t * acct) { - accounts_map::size_type n = accounts.erase(acct->name); - return n > 0; - } - - account_t * find_account(const string& name, bool auto_create = true); - - bool valid() const; - - friend class journal_t; -}; - -std::ostream& operator<<(std::ostream& out, const account_t& account); - - -class func_finalizer_t : public entry_finalizer_t -{ - func_finalizer_t(); - -public: - typedef function func_t; - - func_t func; - - func_finalizer_t(func_t _func) : func(_func) { - TRACE_CTOR(func_finalizer_t, "func_t"); - } - func_finalizer_t(const func_finalizer_t& other) : - entry_finalizer_t(), func(other.func) { - TRACE_CTOR(func_finalizer_t, "copy"); - } - ~func_finalizer_t() throw() { - TRACE_DTOR(func_finalizer_t); - } - - virtual bool operator()(entry_t& entry, bool post) { - return func(entry, post); - } -}; - -template -void add_hook(std::list& list, T obj, const bool prepend = false) { - if (prepend) - list.push_front(obj); - else - list.push_back(obj); -} - -template -void remove_hook(std::list& list, T obj) { - list.remove(obj); -} - -template -bool run_hooks(std::list& list, Data& item, bool post) { - for (typename std::list::const_iterator i = list.begin(); - i != list.end(); - i++) - if (! (*(*i))(item, post)) - return false; - return true; -} - - -typedef std::list entries_list; -typedef std::list auto_entries_list; -typedef std::list period_entries_list; -typedef std::list paths_list; -typedef std::list strings_list; +typedef std::list paths_list; class session_t; +class account_t; class journal_t : public noncopyable { @@ -465,7 +58,7 @@ public: auto_entries_list auto_entries; period_entries_list period_entries; - std::list entry_finalize_hooks; + hooks_t entry_finalize_hooks; journal_t(session_t * _owner); ~journal_t(); @@ -481,10 +74,10 @@ public: bool remove_entry(entry_t * entry); void add_entry_finalizer(entry_finalizer_t * finalizer) { - add_hook(entry_finalize_hooks, finalizer); + entry_finalize_hooks.add_hook(finalizer); } void remove_entry_finalizer(entry_finalizer_t * finalizer) { - remove_hook(entry_finalize_hooks, finalizer); + entry_finalize_hooks.remove_hook(finalizer); } bool valid() const; @@ -541,19 +134,6 @@ public: }; }; -inline void extend_entry_base(journal_t * journal, entry_base_t& entry, - bool post) { - for (auto_entries_list::iterator i = journal->auto_entries.begin(); - i != journal->auto_entries.end(); - i++) - (*i)->extend_entry(entry, post); -} - -inline bool auto_entry_finalizer_t::operator()(entry_t& entry, bool post) { - extend_entry_base(journal, entry, post); - return true; -} - extern const string version; } // namespace ledger diff --git a/main.cc b/main.cc index c79f54dd..6dfe4004 100644 --- a/main.cc +++ b/main.cc @@ -51,8 +51,8 @@ namespace ledger { var_t report(args, 0); var_t ostream(args, 1); - report->transactions_report - (xact_handler_ptr(new format_transactions + report->xacts_report + (xact_handler_ptr(new format_xacts (*ostream, report->session.register_format))); return true; } diff --git a/main.py b/main.py deleted file mode 100644 index 57ba84c5..00000000 --- a/main.py +++ /dev/null @@ -1,373 +0,0 @@ -#!/usr/bin/env python - -# Ledger, the command-line accounting tool -# -# Copyright (c) 2003-2004, New Artisans LLC. All rights reserved. -# -# This program is made available under the terms of the BSD Public -# License. See the LICENSE file included with the distribution for -# details and disclaimer. -# -# This script provides a Python front-end to the ledger library, and -# replicates the functionality of the C++ front-end, main.cc. It is -# provided as an example, and as a starting point for creating custom -# front-ends based on the Ledger module. See the documentation for an -# API reference, and how to use this module. - -import os -import sys -import string -import time - -true, false = 1, 0 - -from ledger import * - -# Create the main journal object, into which all entries will be -# recorded. Once done, the 'journal' may be iterated to yield those -# entries, in the same order as which they appeared in the journal -# file. - -journal = Journal () - -# This call registers all of the default command-line options that -# Ledger supports into the option handling mechanism. Skip this call -# if you wish to do all of your own processing -- in which case simply -# modify the 'config' object however you like. - -add_config_option_handlers () - -averages = {} -compute_monthly_avg = false - -def get_index (xact): - return time.strftime ("%Y/%m", time.localtime (xact.entry.date)) - -class ComputeMonthlyAvg (TransactionHandler): - def __call__ (self, xact): - global averages - index = get_index (xact) - if not averages.has_key(index): - averages[index] = [Value (), 0] - add_transaction_to (xact, averages[index][0]) - averages[index][1] += 1 - TransactionHandler.__call__ (self, xact) - -def monthly_avg (details): - index = get_index (xact) - return averages[index][0] / averages[index][1] - -def show_monthly_averages (arg): - global compute_monthly_avg - compute_monthly_avg = true - config.report_period = "monthly"; - config.total_expr = "@monthly_avg()" - -add_option_handler ("monthly-avg", "", show_monthly_averages) - -# Process the command-line arguments, test whether caching should be -# enabled, and then process any option settings from the execution -# environment. Some historical environment variable names are also -# supported. - -args = process_arguments (sys.argv[1:]) -config.use_cache = not config.data_file -process_environment (os.environ, "LEDGER_") - -if os.environ.has_key ("LEDGER"): - process_option ("file", os.getenv ("LEDGER")) -if os.environ.has_key ("PRICE_HIST"): - process_option ("price-db", os.getenv ("PRICE_HIST")) -if os.environ.has_key ("PRICE_EXP"): - process_option ("price-exp", os.getenv ("PRICE_EXP")) - -# If no argument remain, then no command word was given. Report the -# default help text and exit. - -if len (args) == 0: - option_help () - sys.exit (0) - -# The command word is in the first argument. Canonicalize it to a -# unique, simple form that the remaining code can use to find out -# which command was specified. - -command = args.pop (0); - -if command == "balance" or command == "bal" or command == "b": - command = "b" -elif command == "register" or command == "reg" or command == "r": - command = "r" -elif command == "print" or command == "p": - command = "p" -elif command == "output": - command = "w" -elif command == "emacs": - command = "x" -elif command == "xml": - command = "X" -elif command == "entry": - command = "e" -elif command == "equity": - command = "E" -elif command == "prices": - command = "P" -elif command == "pricesdb": - command = "D"; -else: - print "Unrecognized command:", command - sys.exit (1) - -# Create all the parser objects to be used. They are all registered, -# so that Ledger will try each one in turn whenever it is presented -# with a data file. They are attempted in reverse order to their -# registry. Note that Gnucash parsing is only available if the Ledger -# module was built with such support (which requires the expat C -# library). - -bin_parser = BinaryParser () -gnucash_parser = None -xml_parser = None -try: xml_parser = GnucashParser () -except: pass -try: gnucash_parser = GnucashParser () -except: pass -try: ofx_parser = OfxParser () -except: pass -qif_parser = QifParser () -text_parser = TextualParser () - -register_parser (bin_parser) -if xml_parser: - register_parser (xml_parser) -if gnucash_parser: - register_parser (gnucash_parser) -if ofx_parser: - register_parser (ofx_parser) -register_parser (qif_parser) -register_parser (text_parser) - -# Parse all entries from the user specified locations (found in -# 'config') into the journal object we created. The two parsers given -# as explicit arguments indicate: the parser to be used for standard -# input, and the parser to be used for cache files. - -parse_ledger_data (journal, bin_parser) - -# Now that everything has been correctly parsed (parse_ledger_data -# would have thrown an exception if not), we can take time to further -# process the configuration options. This changes the configuration a -# bit based on previous option settings, the command word, and the -# remaining arguments. - -config.process_options (command, args); - -# If the command is "e", use the method journal.derive_entry to create -# a brand new entry based on the arguments given. - -new_entry = None -if command == "e": - new_entry = derive_new_entry (journal, args) - if new_entry is None: - sys.exit (1) - -# Determine the format string to used, based on the command. - -if config.format_string: - format = config.format_string -elif command == "b": - format = config.balance_format -elif command == "r": - format = config.register_format -elif command == "E": - format = config.equity_format -elif command == "P": - min_val = 0 - def vmin(d, val): - global min_val - if not min_val or val < min_val: - min_val = val - return val - return min_val - - max_val = 0 - def vmax(d, val): - global max_val - if not max_val or val > max_val: - max_val = val - return val - return max_val - - format = config.prices_format -elif command == "D": - format = config.pricesdb_format -elif command == "w": - format = config.write_xact_format -else: - format = config.print_format - -# Configure the output file - -if config.output_file: - out = open (config.output_file, "w") -else: - out = sys.stdout - -# Set the final transaction handler: for balances and equity reports, -# it will simply add the value of the transaction to the account's -# xdata, which is used a bit later to report those totals. For all -# other reports, the transaction data is sent to the configured output -# location (default is sys.stdout). - -if command == "b" or command == "E": - handler = SetAccountValue () -elif command == "p" or command == "e": - handler = FormatEntries (out, format) -elif command == "x": - handler = FormatEmacsTransactions (out) -elif command == "X": - handler = FormatXmlEntries (out, config.show_totals) -else: - handler = FormatTransactions (out, format) - -if command == "w": - write_textual_journal(journal, args, handler, out); -else: - # Chain transaction filters on top of the base handler. Most of these - # filters customize the output for reporting. None of this is done - # for balance or equity reports, which don't need it. - - if not (command == "b" or command == "E"): - if config.head_entries or config.tail_entries: - handler = TruncateEntries (handler, config.head_entries, - config.tail_entries) - - if config.display_predicate: - handler = FilterTransactions (handler, config.display_predicate) - - handler = CalcTransactions (handler) - - if config.reconcile_balance: - reconcilable = False - if config.reconcile_balance == "": - reconcilable = True - else: - target_balance = Value (config.reconcile_balance) - - cutoff = time.time () - if config.reconcile_date: - cutoff = parse_date (config.reconcile_date) - - handler = ReconcileTransactions (handler, target_balance, - cutoff, reconcilable) - - if config.sort_string: - handler = SortTransactions (handler, config.sort_string) - - if config.show_revalued: - handler = ChangedValueTransactions (handler, - config.show_revalued_only) - - if config.show_collapsed: - handler = CollapseTransactions (handler); - - if config.show_subtotal and not (command == "b" or command == "E"): - handler = SubtotalTransactions (handler) - - if config.days_of_the_week: - handler = DowTransactions (handler) - elif config.by_payee: - handler = ByPayeeTransactions (handler) - - if config.report_period: - handler = IntervalTransactions (handler, config.report_period, - config.report_period_sort) - handler = SortTransactions (handler, "d") - - if compute_monthly_avg: - handler = ComputeMonthlyAvg (handler) - - # The next set of transaction filters are used by all reports. - - if config.show_inverted: - handler = InvertTransactions (handler) - - if config.show_related: - handler = RelatedTransactions (handler, config.show_all_related) - - if config.predicate: - handler = FilterTransactions (handler, config.predicate) - - if config.budget_flags: - handler = BudgetTransactions (handler, config.budget_flags) - handler.add_period_entries (journal) - elif config.forecast_limit: - handler = ForecastTransactions (handler, config.forecast_limit) - handler.add_period_entries (journal) - - if config.comm_as_payee: - handler = SetCommAsPayee (handler) - - # Walk the journal's entries, and pass each entry's transaction to the - # handler chain established above. And although a journal's entries - # can be walked using Python, it is significantly faster to do this - # simple walk in C++, using `walk_entries'. - # - # if command == "e": - # for xact in new_entry: - # handler (xact) - # else: - # for entry in journal: - # for xact in entry: - # handler (xact) - - if command == "e": - walk_transactions (new_entry, handler) - elif command == "P" or command == "D": - walk_commodities (handler) - else: - walk_entries (journal, handler) - - # Flush the handlers, causing them to output whatever data is still - # pending. - - if command != "P" and command != "D": - handler.flush () - -# For the balance and equity reports, the account totals now need to -# be displayed. This is different from outputting transactions, in -# that we are now outputting account totals to display a summary of -# the transactions that were just walked. - -if command == "b": - acct_formatter = FormatAccount (out, format, config.display_predicate) - sum_accounts (journal.master) - walk_accounts (journal.master, acct_formatter, config.sort_string) - acct_formatter.final (journal.master) - acct_formatter.flush () - - if account_has_xdata (journal.master): - xdata = account_xdata (journal.master) - if not config.show_collapsed and xdata.total: - out.write("--------------------\n") - xdata.value = xdata.total - # jww (2005-02-15): yet to convert - #acct_formatter.format.format (out, details_t (journal.master)) - -elif command == "E": - acct_formatter = FormatEquity (out, format, config.display_predicate) - sum_accounts (journal.master) - walk_accounts (journal.master, acct_formatter, config.sort_string) - acct_formatter.flush () - -# If it were important to clean things up, we would have to clear out -# the accumulated xdata at this point: - -#clear_all_xdata () - -# If the cache is being used, and is dirty, update it now. - -if config.use_cache and config.cache_dirty and config.cache_file: - write_binary_journal (config.cache_file, journal); - -# We're done! diff --git a/ofx.cc b/ofx.cc index 68a3269f..ae3b5bbc 100644 --- a/ofx.cc +++ b/ofx.cc @@ -49,8 +49,8 @@ int ofx_proc_account_cb(struct OfxAccountData data, void * account_data) return 0; } -int ofx_proc_transaction_cb(struct OfxTransactionData data, - void * transaction_data) +int ofx_proc_xact_cb(struct OfxXactData data, + void * xact_data) { if (! data.account_id_valid || ! data.units_valid) return -1; @@ -61,8 +61,8 @@ int ofx_proc_transaction_cb(struct OfxTransactionData data, entry_t * entry = new entry_t; - entry->add_transaction(new transaction_t(account)); - transaction_t * xact = entry->transactions.back(); + entry->add_xact(new xact_t(account)); + xact_t * xact = entry->xacts.back(); // get the account's default currency commodities_map::iterator ac = ofx_account_currencies.find(data.account_id); @@ -112,7 +112,7 @@ int ofx_proc_transaction_cb(struct OfxTransactionData data, // Balance all entries into , since it is not specified. account = curr_journal->find_account(""); - entry->add_transaction(new transaction_t(account)); + entry->add_xact(new xact_t(account)); if (! curr_journal->add_entry(entry)) { print_entry(std::cerr, *entry); @@ -208,11 +208,11 @@ unsigned int ofx_parser_t::parse(std::istream& in, LibofxContextPtr libofx_context = libofx_get_new_context(); - ofx_set_statement_cb (libofx_context, ofx_proc_statement_cb, 0); - ofx_set_account_cb (libofx_context, ofx_proc_account_cb, 0); - ofx_set_transaction_cb(libofx_context, ofx_proc_transaction_cb, 0); - ofx_set_security_cb (libofx_context, ofx_proc_security_cb, 0); - ofx_set_status_cb (libofx_context, ofx_proc_status_cb, 0); + ofx_set_statement_cb (libofx_context, ofx_proc_statement_cb, 0); + ofx_set_account_cb (libofx_context, ofx_proc_account_cb, 0); + ofx_set_xact_cb (libofx_context, ofx_proc_xact_cb, 0); + ofx_set_security_cb (libofx_context, ofx_proc_security_cb, 0); + ofx_set_status_cb (libofx_context, ofx_proc_status_cb, 0); // The processing is done by way of callbacks, which are all defined // above. diff --git a/op.cc b/op.cc index 618a4e43..c8f38a38 100644 --- a/op.cc +++ b/op.cc @@ -55,9 +55,9 @@ void expr_t::op_t::compute(value_t& result, case AMOUNT: if (details.xact) { - if (transaction_has_xdata(*details.xact) && - transaction_xdata_(*details.xact).dflags & TRANSACTION_COMPOUND) - result = transaction_xdata_(*details.xact).value; + if (xact_has_xdata(*details.xact) && + xact_xdata_(*details.xact).dflags & XACT_COMPOUND) + result = xact_xdata_(*details.xact).value; else result = details.xact->amount; } @@ -72,9 +72,9 @@ void expr_t::op_t::compute(value_t& result, case PRICE: if (details.xact) { bool set = false; - if (transaction_has_xdata(*details.xact)) { - transaction_xdata_t& xdata(transaction_xdata_(*details.xact)); - if (xdata.dflags & TRANSACTION_COMPOUND) { + if (xact_has_xdata(*details.xact)) { + xact_xdata_t& xdata(xact_xdata_(*details.xact)); + if (xdata.dflags & XACT_COMPOUND) { result = xdata.value.value(); set = true; } @@ -98,9 +98,9 @@ void expr_t::op_t::compute(value_t& result, case COST: if (details.xact) { bool set = false; - if (transaction_has_xdata(*details.xact)) { - transaction_xdata_t& xdata(transaction_xdata_(*details.xact)); - if (xdata.dflags & TRANSACTION_COMPOUND) { + if (xact_has_xdata(*details.xact)) { + xact_xdata_t& xdata(xact_xdata_(*details.xact)); + if (xdata.dflags & XACT_COMPOUND) { result = xdata.value.cost(); set = true; } @@ -122,24 +122,24 @@ void expr_t::op_t::compute(value_t& result, break; case TOTAL: - if (details.xact && transaction_has_xdata(*details.xact)) - result = transaction_xdata_(*details.xact).total; + if (details.xact && xact_has_xdata(*details.xact)) + result = xact_xdata_(*details.xact).total; else if (details.account && account_has_xdata(*details.account)) result = account_xdata(*details.account).total; else result = 0L; break; case PRICE_TOTAL: - if (details.xact && transaction_has_xdata(*details.xact)) - result = transaction_xdata_(*details.xact).total.value(); + if (details.xact && xact_has_xdata(*details.xact)) + result = xact_xdata_(*details.xact).total.value(); else if (details.account && account_has_xdata(*details.account)) result = account_xdata(*details.account).total.value(); else result = 0L; break; case COST_TOTAL: - if (details.xact && transaction_has_xdata(*details.xact)) - result = transaction_xdata_(*details.xact).total.cost(); + if (details.xact && xact_has_xdata(*details.xact)) + result = xact_xdata_(*details.xact).total.cost(); else if (details.account && account_has_xdata(*details.account)) result = account_xdata(*details.account).total.cost(); else @@ -160,9 +160,9 @@ void expr_t::op_t::compute(value_t& result, break; case DATE: - if (details.xact && transaction_has_xdata(*details.xact) && - is_valid(transaction_xdata_(*details.xact).date)) - result = transaction_xdata_(*details.xact).date; + if (details.xact && xact_has_xdata(*details.xact) && + is_valid(xact_xdata_(*details.xact).date)) + result = xact_xdata_(*details.xact).date; else if (details.xact) result = details.xact->date(); else if (details.entry) @@ -172,9 +172,9 @@ void expr_t::op_t::compute(value_t& result, break; case ACT_DATE: - if (details.xact && transaction_has_xdata(*details.xact) && - is_valid(transaction_xdata_(*details.xact).date)) - result = transaction_xdata_(*details.xact).date; + if (details.xact && xact_has_xdata(*details.xact) && + is_valid(xact_xdata_(*details.xact).date)) + result = xact_xdata_(*details.xact).date; else if (details.xact) result = details.xact->actual_date(); else if (details.entry) @@ -184,9 +184,9 @@ void expr_t::op_t::compute(value_t& result, break; case EFF_DATE: - if (details.xact && transaction_has_xdata(*details.xact) && - is_valid(transaction_xdata_(*details.xact).date)) - result = transaction_xdata_(*details.xact).date; + if (details.xact && xact_has_xdata(*details.xact) && + is_valid(xact_xdata_(*details.xact).date)) + result = xact_xdata_(*details.xact).date; else if (details.xact) result = details.xact->effective_date(); else if (details.entry) @@ -197,34 +197,34 @@ void expr_t::op_t::compute(value_t& result, case CLEARED: if (details.xact) - result = details.xact->state == transaction_t::CLEARED; + result = details.xact->state == xact_t::CLEARED; else result = false; break; case PENDING: if (details.xact) - result = details.xact->state == transaction_t::PENDING; + result = details.xact->state == xact_t::PENDING; else result = false; break; case REAL: if (details.xact) - result = ! (details.xact->has_flags(TRANSACTION_VIRTUAL)); + result = ! (details.xact->has_flags(XACT_VIRTUAL)); else result = true; break; case ACTUAL: if (details.xact) - result = ! (details.xact->has_flags(TRANSACTION_AUTO)); + result = ! (details.xact->has_flags(XACT_AUTO)); else result = true; break; case INDEX: - if (details.xact && transaction_has_xdata(*details.xact)) - result = long(transaction_xdata_(*details.xact).index + 1); + if (details.xact && xact_has_xdata(*details.xact)) + result = long(xact_xdata_(*details.xact).index + 1); else if (details.account && account_has_xdata(*details.account)) result = long(account_xdata(*details.account).count); else @@ -232,8 +232,8 @@ void expr_t::op_t::compute(value_t& result, break; case COUNT: - if (details.xact && transaction_has_xdata(*details.xact)) - result = long(transaction_xdata_(*details.xact).index + 1); + if (details.xact && xact_has_xdata(*details.xact)) + result = long(xact_xdata_(*details.xact).index + 1); else if (details.account && account_has_xdata(*details.account)) result = long(account_xdata(*details.account).total_count); else @@ -317,9 +317,9 @@ void expr_t::op_t::compute(value_t& result, case F_ARITH_MEAN: { long arg_index = 0; ptr_op_t expr = find_leaf(context, 0, arg_index); - if (details.xact && transaction_has_xdata(*details.xact)) { + if (details.xact && xact_has_xdata(*details.xact)) { expr->compute(result, details, context); - result /= amount_t(long(transaction_xdata_(*details.xact).index + 1)); + result /= amount_t(long(xact_xdata_(*details.xact).index + 1)); } else if (details.account && account_has_xdata(*details.account) && account_xdata(*details.account).total_count) { diff --git a/option.cc b/option.cc index 2edebbef..54ee1851 100644 --- a/option.cc +++ b/option.cc @@ -483,7 +483,7 @@ OPT_BEGIN(trace, "") { // Report filtering OPT_BEGIN(effective, "") { - transaction_t::use_effective_date = true; + xact_t::use_effective_date = true; } OPT_END(effective); OPT_BEGIN(begin, "b:") { diff --git a/qif.cc b/qif.cc index 7652cea8..bb8d2c55 100644 --- a/qif.cc +++ b/qif.cc @@ -42,17 +42,17 @@ unsigned int qif_parser_t::parse(std::istream& in, std::auto_ptr entry; std::auto_ptr amount; - transaction_t * xact; + xact_t * xact; unsigned int count = 0; account_t * misc = NULL; commodity_t * def_commodity = NULL; bool saw_splits = false; bool saw_category = false; - transaction_t * total = NULL; + xact_t * total = NULL; entry.reset(new entry_t); - xact = new transaction_t(master); - entry->add_transaction(xact); + xact = new xact_t(master); + entry->add_xact(xact); pathname = journal.sources.back(); src_idx = journal.sources.size() - 1; @@ -135,7 +135,7 @@ unsigned int qif_parser_t::parse(std::istream& in, c = in.peek(); if (c == '*' || c == 'X') { in.get(c); - xact->state = transaction_t::CLEARED; + xact->state = xact_t::CLEARED; } break; @@ -159,8 +159,8 @@ unsigned int qif_parser_t::parse(std::istream& in, break; case 'S': - xact = new transaction_t(NULL); - entry->add_transaction(xact); + xact = new xact_t(NULL); + entry->add_xact(xact); // fall through... case 'L': { int len = std::strlen(line); @@ -205,10 +205,10 @@ unsigned int qif_parser_t::parse(std::istream& in, } if (! saw_splits) { - transaction_t * nxact = new transaction_t(other); + xact_t * nxact = new xact_t(other); // The amount doesn't need to be set because the code below - // will balance this transaction against the other. - entry->add_transaction(nxact); + // will balance this xact against the other. + entry->add_xact(nxact); } if (journal.add_entry(entry.get())) { @@ -223,8 +223,8 @@ unsigned int qif_parser_t::parse(std::istream& in, // reset things for the next entry entry.reset(new entry_t); - xact = new transaction_t(master); - entry->add_transaction(xact); + xact = new xact_t(master); + entry->add_xact(xact); saw_splits = false; saw_category = false; diff --git a/quotes.cc b/quotes.cc index 15214b47..e2ff97c8 100644 --- a/quotes.cc +++ b/quotes.cc @@ -1,14 +1,9 @@ #include "quotes.h" -#include "datetime.h" -#include "error.h" -#include "debug.h" - -#include -#include -#include +#include "utils.h" namespace ledger { +#if 0 void quotes_by_script::operator()(commodity_base_t& commodity, const datetime_t& moment, const datetime_t& date, @@ -78,5 +73,6 @@ void quotes_by_script::operator()(commodity_base_t& commodity, commodity.symbol + "\")"); } } +#endif } // namespace ledger diff --git a/quotes.h b/quotes.h index 3c457b95..919379d2 100644 --- a/quotes.h +++ b/quotes.h @@ -5,8 +5,8 @@ namespace ledger { -class quotes_by_script - : public noncopyable, commodity_t::base_t::updater_t +#if 0 +class quotes_by_script : public noncopyable, public commodity_t::base_t::updater_t { string price_db; unsigned long pricing_leeway; @@ -32,6 +32,7 @@ public: const datetime_t& last, amount_t& price); }; +#endif } // namespace ledger diff --git a/reconcile.cc b/reconcile.cc index 8a1be816..5d979251 100644 --- a/reconcile.cc +++ b/reconcile.cc @@ -3,14 +3,14 @@ namespace ledger { -#define xact_next(x) ((transaction_t *)transaction_xdata(*x).ptr) -#define xact_next_ptr(x) ((transaction_t **)&transaction_xdata(*x).ptr) +#define xact_next(x) ((xact_t *)xact_xdata(*x).ptr) +#define xact_next_ptr(x) ((xact_t **)&xact_xdata(*x).ptr) static bool search_for_balance(amount_t& amount, - transaction_t ** prev, transaction_t * next) + xact_t ** prev, xact_t * next) { for (; next; next = xact_next(next)) { - transaction_t * temp = *prev; + xact_t * temp = *prev; *prev = next; amount -= next->amount; @@ -24,32 +24,32 @@ static bool search_for_balance(amount_t& amount, return false; } -void reconcile_transactions::push_to_handler(transaction_t * first) +void reconcile_xacts::push_to_handler(xact_t * first) { for (; first; first = xact_next(first)) - item_handler::operator()(*first); + item_handler::operator()(*first); - item_handler::flush(); + item_handler::flush(); } -void reconcile_transactions::flush() +void reconcile_xacts::flush() { value_t cleared_balance; value_t pending_balance; - transaction_t * first = NULL; - transaction_t ** last_ptr = &first; + xact_t * first = NULL; + xact_t ** last_ptr = &first; - for (transactions_list::iterator x = xacts.begin(); + for (xacts_list::iterator x = xacts.begin(); x != xacts.end(); x++) { if (! is_valid(cutoff) || (*x)->date() < cutoff) { switch ((*x)->state) { - case transaction_t::CLEARED: + case xact_t::CLEARED: cleared_balance += (*x)->amount; break; - case transaction_t::UNCLEARED: - case transaction_t::PENDING: + case xact_t::UNCLEARED: + case xact_t::PENDING: pending_balance += (*x)->amount; *last_ptr = *x; last_ptr = xact_next_ptr(*x); diff --git a/reconcile.h b/reconcile.h index 9f672d6b..c6affb81 100644 --- a/reconcile.h +++ b/reconcile.h @@ -6,32 +6,32 @@ namespace ledger { -class reconcile_transactions : public item_handler +class reconcile_xacts : public item_handler { value_t balance; datetime_t cutoff; - transactions_list xacts; + xacts_list xacts; - reconcile_transactions(); + reconcile_xacts(); public: - reconcile_transactions(xact_handler_ptr handler, + reconcile_xacts(xact_handler_ptr handler, const value_t& _balance, const datetime_t& _cutoff) - : item_handler(handler), + : item_handler(handler), balance(_balance), cutoff(_cutoff) { - TRACE_CTOR(reconcile_transactions, + TRACE_CTOR(reconcile_xacts, "xact_handler_ptr, const value_t&, const datetime_t&"); } - virtual ~reconcile_transactions() throw() { - TRACE_DTOR(reconcile_transactions); + virtual ~reconcile_xacts() throw() { + TRACE_DTOR(reconcile_xacts); } - void push_to_handler(transaction_t * first); + void push_to_handler(xact_t * first); virtual void flush(); - virtual void operator()(transaction_t& xact) { + virtual void operator()(xact_t& xact) { xacts.push_back(&xact); } }; diff --git a/report.cc b/report.cc index 3742e020..51516acd 100644 --- a/report.cc +++ b/report.cc @@ -36,34 +36,34 @@ namespace ledger { xact_handler_ptr report_t::chain_xact_handlers(xact_handler_ptr base_handler, - const bool handle_individual_transactions) + const bool handle_individual_xacts) { bool remember_components = false; xact_handler_ptr handler(base_handler); - // format_transactions write each transaction received to the + // format_xacts write each xact received to the // output stream. - if (handle_individual_transactions) { + if (handle_individual_xacts) { // truncate_entries cuts off a certain number of _entries_ from // being displayed. It does not affect calculation. if (head_entries || tail_entries) handler.reset(new truncate_entries(handler, head_entries, tail_entries)); - // filter_transactions will only pass through transactions + // filter_xacts will only pass through xacts // matching the `display_predicate'. if (! display_predicate.empty()) - handler.reset(new filter_transactions(handler, display_predicate)); + handler.reset(new filter_xacts(handler, display_predicate)); - // calc_transactions computes the running total. When this + // calc_xacts computes the running total. When this // appears will determine, for example, whether filtered - // transactions are included or excluded from the running total. - handler.reset(new calc_transactions(handler)); + // xacts are included or excluded from the running total. + handler.reset(new calc_xacts(handler)); - // component_transactions looks for reported transaction that + // component_xacts looks for reported xact that // match the given `descend_expr', and then reports the - // transactions which made up the total for that reported - // transaction. + // xacts which made up the total for that reported + // xact. if (! descend_expr.empty()) { std::list descend_exprs; @@ -78,126 +78,126 @@ report_t::chain_xact_handlers(xact_handler_ptr base_handler, descend_exprs.rbegin(); i != descend_exprs.rend(); i++) - handler.reset(new component_transactions(handler, *i)); + handler.reset(new component_xacts(handler, *i)); remember_components = true; } - // reconcile_transactions will pass through only those - // transactions which can be reconciled to a given balance - // (calculated against the transactions which it receives). + // reconcile_xacts will pass through only those + // xacts which can be reconciled to a given balance + // (calculated against the xacts which it receives). if (! reconcile_balance.empty()) { datetime_t cutoff = current_moment; if (! reconcile_date.empty()) cutoff = parse_datetime(reconcile_date); - handler.reset(new reconcile_transactions + handler.reset(new reconcile_xacts (handler, value_t(reconcile_balance), cutoff)); } - // filter_transactions will only pass through transactions + // filter_xacts will only pass through xacts // matching the `secondary_predicate'. if (! secondary_predicate.empty()) - handler.reset(new filter_transactions(handler, secondary_predicate)); + handler.reset(new filter_xacts(handler, secondary_predicate)); - // sort_transactions will sort all the transactions it sees, based + // sort_xacts will sort all the xacts it sees, based // on the `sort_order' value expression. if (! sort_string.empty()) { if (entry_sort) handler.reset(new sort_entries(handler, sort_string)); else - handler.reset(new sort_transactions(handler, sort_string)); + handler.reset(new sort_xacts(handler, sort_string)); } - // changed_value_transactions adds virtual transactions to the + // changed_value_xacts adds virtual xacts to the // list to account for changes in market value of commodities, // which otherwise would affect the running total unpredictably. if (show_revalued) - handler.reset(new changed_value_transactions(handler, show_revalued_only)); + handler.reset(new changed_value_xacts(handler, show_revalued_only)); - // collapse_transactions causes entries with multiple transactions - // to appear as entries with a subtotaled transaction for each + // collapse_xacts causes entries with multiple xacts + // to appear as entries with a subtotaled xact for each // commodity used. if (show_collapsed) - handler.reset(new collapse_transactions(handler)); + handler.reset(new collapse_xacts(handler)); - // subtotal_transactions combines all the transactions it receives - // into one subtotal entry, which has one transaction for each + // subtotal_xacts combines all the xacts it receives + // into one subtotal entry, which has one xact for each // commodity in each account. // - // period_transactions is like subtotal_transactions, but it + // period_xacts is like subtotal_xacts, but it // subtotals according to time periods rather than totalling // everything. // - // dow_transactions is like period_transactions, except that it - // reports all the transactions that fall on each subsequent day + // dow_xacts is like period_xacts, except that it + // reports all the xacts that fall on each subsequent day // of the week. if (show_subtotal) - handler.reset(new subtotal_transactions(handler, remember_components)); + handler.reset(new subtotal_xacts(handler, remember_components)); if (days_of_the_week) - handler.reset(new dow_transactions(handler, remember_components)); + handler.reset(new dow_xacts(handler, remember_components)); else if (by_payee) - handler.reset(new by_payee_transactions(handler, remember_components)); + handler.reset(new by_payee_xacts(handler, remember_components)); - // interval_transactions groups transactions together based on a + // interval_xacts groups xacts together based on a // time period, such as weekly or monthly. if (! report_period.empty()) { - handler.reset(new interval_transactions(handler, report_period, + handler.reset(new interval_xacts(handler, report_period, remember_components)); - handler.reset(new sort_transactions(handler, "d")); + handler.reset(new sort_xacts(handler, "d")); } } - // invert_transactions inverts the value of the transactions it + // invert_xacts inverts the value of the xacts it // receives. if (show_inverted) - handler.reset(new invert_transactions(handler)); + handler.reset(new invert_xacts(handler)); - // related_transactions will pass along all transactions related - // to the transaction received. If `show_all_related' is true, - // then all the entry's transactions are passed; meaning that if - // one transaction of an entry is to be printed, all the - // transaction for that entry will be printed. + // related_xacts will pass along all xacts related + // to the xact received. If `show_all_related' is true, + // then all the entry's xacts are passed; meaning that if + // one xact of an entry is to be printed, all the + // xact for that entry will be printed. if (show_related) - handler.reset(new related_transactions(handler, show_all_related)); + handler.reset(new related_xacts(handler, show_all_related)); - // This filter_transactions will only pass through transactions + // This filter_xacts will only pass through xacts // matching the `predicate'. if (! predicate.empty()) - handler.reset(new filter_transactions(handler, predicate)); + handler.reset(new filter_xacts(handler, predicate)); #if 0 - // budget_transactions takes a set of transactions from a data - // file and uses them to generate "budget transactions" which - // balance against the reported transactions. + // budget_xacts takes a set of xacts from a data + // file and uses them to generate "budget xacts" which + // balance against the reported xacts. // - // forecast_transactions is a lot like budget_transactions, except + // forecast_xacts is a lot like budget_xacts, except // that it adds entries only for the future, and does not balance // them against anything but the future balance. if (budget_flags) { - budget_transactions * budget_handler - = new budget_transactions(handler, budget_flags); + budget_xacts * budget_handler + = new budget_xacts(handler, budget_flags); budget_handler->add_period_entries(journal->period_entries); handler.reset(budget_handler; // Apply this before the budget handler, so that only matching - // transactions are calculated toward the budget. The use of - // filter_transactions above will further clean the results so - // that no automated transactions that don't match the filter get + // xacts are calculated toward the budget. The use of + // filter_xacts above will further clean the results so + // that no automated xacts that don't match the filter get // reported. if (! predicate.empty()) - handler.reset(new filter_transactions(handler, predicate)); + handler.reset(new filter_xacts(handler, predicate)); } else if (! forecast_limit.empty()) { - forecast_transactions * forecast_handler - = new forecast_transactions(handler, forecast_limit); + forecast_xacts * forecast_handler + = new forecast_xacts(handler, forecast_limit); forecast_handler->add_period_entries(journal->period_entries); handler.reset(forecast_handler; - // See above, under budget_transactions. + // See above, under budget_xacts. if (! predicate.empty()) - handler.reset(new filter_transactions(handler, predicate)); + handler.reset(new filter_xacts(handler, predicate)); } #endif @@ -209,30 +209,30 @@ report_t::chain_xact_handlers(xact_handler_ptr base_handler, return handler; } -void report_t::transactions_report(xact_handler_ptr handler) +void report_t::xacts_report(xact_handler_ptr handler) { - session_transactions_iterator walker(session); - pass_down_transactions(chain_xact_handlers(handler), walker); + session_xacts_iterator walker(session); + pass_down_xacts(chain_xact_handlers(handler), walker); handler->flush(); if (DO_VERIFY()) - session.clean_transactions(); + session.clean_xacts(); } void report_t::entry_report(xact_handler_ptr handler, entry_t& entry) { - entry_transactions_iterator walker(entry); - pass_down_transactions(chain_xact_handlers(handler), walker); + entry_xacts_iterator walker(entry); + pass_down_xacts(chain_xact_handlers(handler), walker); handler->flush(); if (DO_VERIFY()) - session.clean_transactions(entry); + session.clean_xacts(entry); } void report_t::sum_all_accounts() { - session_transactions_iterator walker(session); - pass_down_transactions + session_xacts_iterator walker(session); + pass_down_xacts (chain_xact_handlers(xact_handler_ptr(new set_account_value), false), walker); // no flush() needed with set_account_value @@ -265,7 +265,7 @@ void report_t::accounts_report(acct_handler_ptr handler, } if (DO_VERIFY()) { - session.clean_transactions(); + session.clean_xacts(); session.clean_accounts(); } } diff --git a/report.h b/report.h index 7c5c6384..79d18f3c 100644 --- a/report.h +++ b/report.h @@ -182,7 +182,7 @@ public: chain_xact_handlers(xact_handler_ptr handler, const bool handle_individual_transactions = true); - void transactions_report(xact_handler_ptr handler); + void xacts_report(xact_handler_ptr handler); void entry_report(xact_handler_ptr handler, entry_t& entry); diff --git a/scope.cc b/scope.cc index 872c5454..7a349949 100644 --- a/scope.cc +++ b/scope.cc @@ -52,21 +52,8 @@ void symbol_scope_t::define(const string& name, expr_t::ptr_op_t def) } } -value_t get_amount(scope_t& scope) -{ - assert("I can't get the amount!"); - return NULL_VALUE; -} - expr_t::ptr_op_t symbol_scope_t::lookup(const string& name) { - switch (name[0]) { - case 'a': - if (name[1] == '\0' || name == "amount") - return WRAP_FUNCTOR(bind(get_amount, _1)); - break; - } - symbol_map::const_iterator i = symbols.find(name); if (i != symbols.end()) return (*i).second; diff --git a/scope.h b/scope.h index 1abde444..1bf50a3e 100644 --- a/scope.h +++ b/scope.h @@ -60,9 +60,9 @@ public: class child_scope_t : public noncopyable, public scope_t { +public: scope_t * parent; -public: explicit child_scope_t() : parent(NULL) { TRACE_CTOR(child_scope_t, ""); } diff --git a/session.cc b/session.cc index efb38d89..18435fe6 100644 --- a/session.cc +++ b/session.cc @@ -237,17 +237,17 @@ account_t * session_t::find_account_re(const string& regexp) return find_account_re_(master, mask_t(regexp)); } -void session_t::clean_transactions() +void session_t::clean_xacts() { - session_transactions_iterator walker(*this); - pass_down_transactions - (xact_handler_ptr(new clear_transaction_xdata), walker); + session_xacts_iterator walker(*this); + pass_down_xacts + (xact_handler_ptr(new clear_xact_xdata), walker); } -void session_t::clean_transactions(entry_t& entry) +void session_t::clean_xacts(entry_t& entry) { - entry_transactions_iterator walker(entry); - pass_down_transactions(xact_handler_ptr(new clear_transaction_xdata), walker); + entry_xacts_iterator walker(entry); + pass_down_xacts(xact_handler_ptr(new clear_xact_xdata), walker); } void session_t::clean_accounts() diff --git a/session.h b/session.h index 944b9ce2..36d0470f 100644 --- a/session.h +++ b/session.h @@ -34,6 +34,7 @@ #include "scope.h" #include "journal.h" +#include "account.h" namespace ledger { @@ -165,8 +166,8 @@ public: void clean_accounts(); - void clean_transactions(); - void clean_transactions(entry_t& entry); + void clean_xacts(); + void clean_xacts(entry_t& entry); // // Scope members diff --git a/test.py b/test.py deleted file mode 100755 index 49276de0..00000000 --- a/test.py +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/env python - -from amounts import * - -amt_ncd = Amount("100") -print amt_ncd -amt_nc = Amount("100.00") -print amt_nc -amt = Amount("$100.00") -print amt -namt_ncd = Amount("-100") -print namt_ncd -namt_nc = Amount("-100.00") -print namt_nc -namt = Amount("$-100.00") -print namt -namt2 = Amount("-$100.00") -print namt2 - -val = Value("$100.00") - -print val diff --git a/textual.cc b/textual.cc index c309801e..61fe66db 100644 --- a/textual.cc +++ b/textual.cc @@ -48,10 +48,10 @@ struct time_entry_t #endif namespace { - expr_t parse_amount_expr(std::istream& in, - amount_t& amount, - transaction_t * xact, - unsigned short flags = 0) + optional parse_amount_expr(std::istream& in, + amount_t& amount, + xact_t * xact, + unsigned short flags = 0) { expr_t expr(in, flags | EXPR_PARSE_PARTIAL); @@ -67,33 +67,27 @@ namespace { } #endif -#if 0 if (expr) { - if (! expr_t::compute_amount(expr, amount, xact)) - throw new parse_error("Amount expression failed to compute"); + expr.compile(*xact); -#if 0 - if (expr->kind == expr_t::node_t::VALUE) { - expr = NULL; + if (expr.is_constant()) { + amount = expr.constant_value().as_amount(); + DEBUG("ledger.textual.parse", "line " << linenum << ": " << + "The transaction amount is " << amount); + return expr_t(); // we will fill this in with text } else { - DEBUG_IF("ledger.textual.parse") { + if (SHOW_DEBUG("ledger.textual.parse")) { std::cout << "Value expression tree:" << std::endl; - ledger::dump_value_expr(std::cout, expr.get()); + expr.dump(std::cout); } + return expr; } -#else - expr = value_expr(); -#endif } -#endif - - DEBUG("ledger.textual.parse", "line " << linenum << ": " << - "The transaction amount is " << xact->amount); - return expr; + return none; } } -transaction_t * parse_transaction(char * line, account_t * account, +xact_t * parse_xact(char * line, account_t * account, entry_t * entry = NULL) { std::istringstream in(line); @@ -102,7 +96,7 @@ transaction_t * parse_transaction(char * line, account_t * account, try { // The account will be determined later... - std::auto_ptr xact(new transaction_t(NULL)); + std::auto_ptr xact(new xact_t(NULL)); if (entry) xact->entry = entry; @@ -111,14 +105,14 @@ transaction_t * parse_transaction(char * line, account_t * account, char p = peek_next_nonws(in); switch (p) { case '*': - xact->state = transaction_t::CLEARED; + xact->state = xact_t::CLEARED; in.get(p); p = peek_next_nonws(in); DEBUG("ledger.textual.parse", "line " << linenum << ": " << "Parsed the CLEARED flag"); break; case '!': - xact->state = transaction_t::PENDING; + xact->state = xact_t::PENDING; in.get(p); p = peek_next_nonws(in); DEBUG("ledger.textual.parse", "line " << linenum << ": " << @@ -146,11 +140,11 @@ transaction_t * parse_transaction(char * line, account_t * account, char * e = &line[account_end]; if ((*b == '[' && *(e - 1) == ']') || (*b == '(' && *(e - 1) == ')')) { - xact->add_flags(TRANSACTION_VIRTUAL); + xact->add_flags(XACT_VIRTUAL); DEBUG("ledger.textual.parse", "line " << linenum << ": " << "Parsed a virtual account name"); if (*b == '[') { - xact->add_flags(TRANSACTION_BALANCE); + xact->add_flags(XACT_BALANCE); DEBUG("ledger.textual.parse", "line " << linenum << ": " << "Parsed a balanced virtual account name"); } @@ -199,7 +193,7 @@ transaction_t * parse_transaction(char * line, account_t * account, // always NULL right now if (xact->amount_expr) { unsigned long end = (long)in.tellg(); - xact->amount_expr.set_text(string(line, beg, end - beg)); + xact->amount_expr->set_text(string(line, beg, end - beg)); } } catch (error * err) { @@ -234,22 +228,28 @@ transaction_t * parse_transaction(char * line, account_t * account, try { unsigned long beg = (long)in.tellg(); - if (parse_amount_expr(in, *xact->cost, xact.get(), + if (optional cost_expr = + parse_amount_expr(in, *xact->cost, xact.get(), EXPR_PARSE_NO_MIGRATE | - EXPR_PARSE_NO_ASSIGN)) - throw new parse_error - ("A transaction's cost must evaluate to a constant value"); - assert(xact->cost->valid()); - - // jww (2008-07-24): I don't think this is right... - if (xact->cost_expr) { - unsigned long end = (long)in.tellg(); - if (per_unit) - xact->cost_expr->set_text(string("@") + - string(line, beg, end - beg)); - else - xact->cost_expr->set_text(string("@@") + - string(line, beg, end - beg)); + EXPR_PARSE_NO_ASSIGN)) { + try { + *xact->cost = cost_expr->calc(*xact).as_amount(); + assert(xact->cost->valid()); + + xact->cost_expr = cost_expr; + + unsigned long end = (long)in.tellg(); + if (per_unit) + xact->cost_expr->set_text(string("@") + + string(line, beg, end - beg)); + else + xact->cost_expr->set_text(string("@@") + + string(line, beg, end - beg)); + } + catch (...) { + throw new parse_error + ("A transaction's cost must evaluate to a constant value"); + } } } catch (error * err) { @@ -347,11 +347,11 @@ transaction_t * parse_transaction(char * line, account_t * account, if (! diff.is_realzero()) { if (xact->amount) { - transaction_t * temp = - new transaction_t(xact->account, diff, - TRANSACTION_GENERATED | - TRANSACTION_CALCULATED); - entry->add_transaction(temp); + xact_t * temp = + new xact_t(xact->account, diff, + XACT_GENERATED | + XACT_CALCULATED); + entry->add_xact(temp); DEBUG("ledger.textual.parse", "line " << linenum << ": " << "Created balancing transaction"); @@ -416,7 +416,7 @@ transaction_t * parse_transaction(char * line, account_t * account, } } -bool parse_transactions(std::istream& in, +bool parse_xacts(std::istream& in, account_t * account, entry_base_t& entry, const string& kind, @@ -444,8 +444,8 @@ bool parse_transactions(std::istream& in, if (! *p) break; } - if (transaction_t * xact = parse_transaction(line, account)) { - entry.add_transaction(xact); + if (xact_t * xact = parse_xact(line, account)) { + entry.add_xact(xact); added = true; } } @@ -474,15 +474,15 @@ entry_t * parse_entry(std::istream& in, char * line, account_t * master, // Parse the optional cleared flag: * - transaction_t::state_t state = transaction_t::UNCLEARED; + xact_t::state_t state = xact_t::UNCLEARED; if (next) { switch (*next) { case '*': - state = transaction_t::CLEARED; + state = xact_t::CLEARED; next = skip_ws(++next); break; case '!': - state = transaction_t::PENDING; + state = xact_t::PENDING; next = skip_ws(++next); break; } @@ -504,7 +504,7 @@ entry_t * parse_entry(std::istream& in, char * line, account_t * master, TRACE_STOP(entry_text, 1); - // Parse all of the transactions associated with this entry + // Parse all of the xacts associated with this entry TRACE_START(entry_details, 1, "Time spent parsing entry details:"); @@ -532,9 +532,9 @@ entry_t * parse_entry(std::istream& in, char * line, account_t * master, break; } - if (transaction_t * xact = parse_transaction(line, master, curr.get())) { - if (state != transaction_t::UNCLEARED && - xact->state == transaction_t::UNCLEARED) + if (xact_t * xact = parse_xact(line, master, curr.get())) { + if (state != xact_t::UNCLEARED && + xact->state == xact_t::UNCLEARED) xact->state = state; xact->beg_pos = beg_pos; @@ -543,7 +543,7 @@ entry_t * parse_entry(std::istream& in, char * line, account_t * master, xact->end_line = linenum; pos = end_pos; - curr->add_transaction(xact); + curr->add_xact(xact); } if (in.eof()) @@ -651,10 +651,10 @@ static void clock_out_from_timelog(std::list& time_entries, amt.parse(buf); assert(amt.valid()); - transaction_t * xact - = new transaction_t(event.account, amt, TRANSACTION_VIRTUAL); - xact->state = transaction_t::CLEARED; - curr->add_transaction(xact); + xact_t * xact + = new xact_t(event.account, amt, XACT_VIRTUAL); + xact->state = xact_t::CLEARED; + curr->add_xact(xact); if (! journal.add_entry(curr.get())) throw new parse_error("Failed to record 'out' timelog entry"); @@ -854,7 +854,7 @@ unsigned int textual_parser_t::parse(std::istream& in, } auto_entry_t * ae = new auto_entry_t(skip_ws(line + 1)); - if (parse_transactions(in, account_stack.front(), *ae, + if (parse_xacts(in, account_stack.front(), *ae, "automated", end_pos)) { journal.auto_entries.push_back(ae); ae->src_idx = src_idx; @@ -871,7 +871,7 @@ unsigned int textual_parser_t::parse(std::istream& in, if (! pe->period) throw new parse_error(string("Parsing time period '") + line + "'"); - if (parse_transactions(in, account_stack.front(), *pe, + if (parse_xacts(in, account_stack.front(), *pe, "period", end_pos)) { if (pe->finalize()) { extend_entry_base(&journal, *pe, true); @@ -939,7 +939,7 @@ unsigned int textual_parser_t::parse(std::istream& in, // Once we have an alias name (b) and the target account // name (e), add a reference to the account in the - // `account_aliases' map, which is used by the transaction + // `account_aliases' map, which is used by the xact // parser to resolve alias references. account_t * acct = account_stack.front()->find_account(e); std::pair result @@ -1029,10 +1029,11 @@ unsigned int textual_parser_t::parse(std::istream& in, return count; } -void write_textual_journal(journal_t& journal, path pathname, - item_handler& formatter, - const string& write_hdr_format, - std::ostream& out) +void write_textual_journal(journal_t& journal, + const path& pathname, + xact_handler_ptr formatter, + const string& write_hdr_format, + std::ostream& out) { unsigned long index = 0; path found; @@ -1102,14 +1103,14 @@ void write_textual_journal(journal_t& journal, path pathname, char c; if (base) { - for (transactions_list::iterator x = base->transactions.begin(); - x != base->transactions.end(); + for (xacts_list::iterator x = base->xacts.begin(); + x != base->xacts.end(); x++) - if (! (*x)->has_flags(TRANSACTION_AUTO)) { - transaction_xdata(**x).dflags |= TRANSACTION_TO_DISPLAY; - formatter(**x); + if (! (*x)->has_flags(XACT_AUTO)) { + xact_xdata(**x).dflags |= XACT_TO_DISPLAY; + (*formatter)(**x); } - formatter.flush(); + formatter->flush(); while (pos < base->end_pos) { in.get(c); diff --git a/textual.h b/textual.h index 71e44a94..438d5ea2 100644 --- a/textual.h +++ b/textual.h @@ -19,13 +19,14 @@ public: const path * original_file = NULL); }; -transaction_t * parse_transaction_text(char * line, account_t * account); -transaction_t * parse_transaction(std::istream& in, account_t * account); - -void write_textual_journal(journal_t& journal, path pathname, - item_handler& formatter, - const string& write_hdr_format, - std::ostream& out); +xact_t * parse_xact_text(char * line, account_t * account); +xact_t * parse_xact(std::istream& in, account_t * account); + +void write_textual_journal(journal_t& journal, + const path& pathname, + xact_handler_ptr& formatter, + const string& write_hdr_format, + std::ostream& out); class include_context : public file_context { diff --git a/walk.cc b/walk.cc index b0aa31f6..26555ec6 100644 --- a/walk.cc +++ b/walk.cc @@ -8,25 +8,25 @@ namespace ledger { template <> -bool compare_items::operator()(const transaction_t * left, - const transaction_t * right) +bool compare_items::operator()(const xact_t * left, + const xact_t * right) { assert(left); assert(right); #if 0 - transaction_xdata_t& lxdata(transaction_xdata(*left)); - if (! (lxdata.dflags & TRANSACTION_SORT_CALC)) { + xact_xdata_t& lxdata(xact_xdata(*left)); + if (! (lxdata.dflags & XACT_SORT_CALC)) { sort_order.compute(lxdata.sort_value, details_t(*left)); lxdata.sort_value.reduce(); - lxdata.dflags |= TRANSACTION_SORT_CALC; + lxdata.dflags |= XACT_SORT_CALC; } - transaction_xdata_t& rxdata(transaction_xdata(*right)); - if (! (rxdata.dflags & TRANSACTION_SORT_CALC)) { + xact_xdata_t& rxdata(xact_xdata(*right)); + if (! (rxdata.dflags & XACT_SORT_CALC)) { sort_order.compute(rxdata.sort_value, details_t(*right)); rxdata.sort_value.reduce(); - rxdata.dflags |= TRANSACTION_SORT_CALC; + rxdata.dflags |= XACT_SORT_CALC; } DEBUG("ledger.walk.compare_items_xact", @@ -40,18 +40,18 @@ bool compare_items::operator()(const transaction_t * left, #endif } -transaction_xdata_t& transaction_xdata(const transaction_t& xact) +xact_xdata_t& xact_xdata(const xact_t& xact) { if (! xact.data) - xact.data = new transaction_xdata_t(); - return *((transaction_xdata_t *) xact.data); + xact.data = new xact_xdata_t(); + return *((xact_xdata_t *) xact.data); } -void add_transaction_to(const transaction_t& xact, value_t& value) +void add_xact_to(const xact_t& xact, value_t& value) { - if (transaction_has_xdata(xact) && - transaction_xdata_(xact).dflags & TRANSACTION_COMPOUND) { - value += transaction_xdata_(xact).value; + if (xact_has_xdata(xact) && + xact_xdata_(xact).dflags & XACT_COMPOUND) { + value += xact_xdata_(xact).value; } else if (xact.cost || (! value.is_null() && ! value.is_realzero())) { // jww (2008-04-24): Is this costly? @@ -92,7 +92,7 @@ entry_t * entries_iterator::operator()() return *entries_i++; } -void session_transactions_iterator::reset(session_t& session) +void session_xacts_iterator::reset(session_t& session) { entries.reset(session); entry_t * entry = entries(); @@ -100,9 +100,9 @@ void session_transactions_iterator::reset(session_t& session) xacts.reset(*entry); } -transaction_t * session_transactions_iterator::operator()() +xact_t * session_xacts_iterator::operator()() { - transaction_t * xact = xacts(); + xact_t * xact = xacts(); if (xact == NULL) { entry_t * entry = entries(); if (entry != NULL) { @@ -121,7 +121,7 @@ void truncate_entries::flush() entry_t * last_entry = (*xacts.begin())->entry; int l = 0; - for (transactions_list::iterator x = xacts.begin(); + for (xacts_list::iterator x = xacts.begin(); x != xacts.end(); x++) if (last_entry != (*x)->entry) { @@ -133,7 +133,7 @@ void truncate_entries::flush() last_entry = (*xacts.begin())->entry; int i = 0; - for (transactions_list::iterator x = xacts.begin(); + for (xacts_list::iterator x = xacts.begin(); x != xacts.end(); x++) { if (last_entry != (*x)->entry) { @@ -157,60 +157,60 @@ void truncate_entries::flush() } if (print) - item_handler::operator()(**x); + item_handler::operator()(**x); } xacts.clear(); - item_handler::flush(); + item_handler::flush(); } -void set_account_value::operator()(transaction_t& xact) +void set_account_value::operator()(xact_t& xact) { account_t * acct = xact_account(xact); assert(acct); account_xdata_t& xdata = account_xdata(*acct); - add_transaction_to(xact, xdata.value); + add_xact_to(xact, xdata.value); xdata.count++; - if (xact.has_flags(TRANSACTION_VIRTUAL)) + if (xact.has_flags(XACT_VIRTUAL)) xdata.virtuals++; - item_handler::operator()(xact); + item_handler::operator()(xact); } -void sort_transactions::post_accumulated_xacts() +void sort_xacts::post_accumulated_xacts() { - std::stable_sort(transactions.begin(), transactions.end(), - compare_items(sort_order)); + std::stable_sort(xacts.begin(), xacts.end(), + compare_items(sort_order)); - for (transactions_deque::iterator i = transactions.begin(); - i != transactions.end(); + for (xacts_deque::iterator i = xacts.begin(); + i != xacts.end(); i++) { - transaction_xdata(**i).dflags &= ~TRANSACTION_SORT_CALC; - item_handler::operator()(**i); + xact_xdata(**i).dflags &= ~XACT_SORT_CALC; + item_handler::operator()(**i); } - transactions.clear(); + xacts.clear(); } -void calc_transactions::operator()(transaction_t& xact) +void calc_xacts::operator()(xact_t& xact) { try { - transaction_xdata_t& xdata(transaction_xdata(xact)); + xact_xdata_t& xdata(xact_xdata(xact)); - if (last_xact && transaction_has_xdata(*last_xact)) { - xdata.total += transaction_xdata_(*last_xact).total; - xdata.index = transaction_xdata_(*last_xact).index + 1; + if (last_xact && xact_has_xdata(*last_xact)) { + xdata.total += xact_xdata_(*last_xact).total; + xdata.index = xact_xdata_(*last_xact).index + 1; } else { xdata.index = 0; } - if (! (xdata.dflags & TRANSACTION_NO_TOTAL)) - add_transaction_to(xact, xdata.total); + if (! (xdata.dflags & XACT_NO_TOTAL)) + add_xact_to(xact, xdata.total); - item_handler::operator()(xact); + item_handler::operator()(xact); last_xact = &xact; @@ -222,18 +222,18 @@ void calc_transactions::operator()(transaction_t& xact) } } -void invert_transactions::operator()(transaction_t& xact) +void invert_xacts::operator()(xact_t& xact) { - if (transaction_has_xdata(xact) && - transaction_xdata_(xact).dflags & TRANSACTION_COMPOUND) { - transaction_xdata_(xact).value.negate(); + if (xact_has_xdata(xact) && + xact_xdata_(xact).dflags & XACT_COMPOUND) { + xact_xdata_(xact).value.negate(); } else { xact.amount.negate(); if (xact.cost) xact.cost->negate(); } - item_handler::operator()(xact); + item_handler::operator()(xact); } @@ -242,35 +242,35 @@ void handle_value(const value_t& value, account_t * account, entry_t * entry, unsigned int flags, - std::list& temps, - item_handler& handler, + std::list& temps, + item_handler& handler, const datetime_t& date = datetime_t(), - transactions_list * component_xacts = NULL) + xacts_list * component_xacts = NULL) { - temps.push_back(transaction_t(account)); - transaction_t& xact(temps.back()); + temps.push_back(xact_t(account)); + xact_t& xact(temps.back()); xact.entry = entry; - xact.add_flags(TRANSACTION_BULK_ALLOC); - entry->add_transaction(&xact); + xact.add_flags(XACT_BULK_ALLOC); + entry->add_xact(&xact); - // If there are component transactions to associate with this + // If there are component xacts to associate with this // temporary, do so now. if (component_xacts) - transaction_xdata(xact).copy_component_xacts(*component_xacts); + xact_xdata(xact).copy_component_xacts(*component_xacts); - // If the account for this transaction is all virtual, then report - // the transaction as such. This allows subtotal reports to show - // "(Account)" for accounts that contain only virtual transactions. + // If the account for this xact is all virtual, then report + // the xact as such. This allows subtotal reports to show + // "(Account)" for accounts that contain only virtual xacts. if (account && account_has_xdata(*account)) if (! (account_xdata_(*account).dflags & ACCOUNT_HAS_NON_VIRTUALS)) { - xact.add_flags(TRANSACTION_VIRTUAL); + xact.add_flags(XACT_VIRTUAL); if (! (account_xdata_(*account).dflags & ACCOUNT_HAS_UNB_VIRTUALS)) - xact.add_flags(TRANSACTION_BALANCE); + xact.add_flags(XACT_BALANCE); } - transaction_xdata_t& xdata(transaction_xdata(xact)); + xact_xdata_t& xdata(xact_xdata(xact)); if (is_valid(date)) xdata.date = date; @@ -291,7 +291,7 @@ void handle_value(const value_t& value, case value_t::BALANCE: case value_t::BALANCE_PAIR: xdata.value = temp; - flags |= TRANSACTION_COMPOUND; + flags |= XACT_COMPOUND; break; default: @@ -305,12 +305,12 @@ void handle_value(const value_t& value, handler(xact); } -void collapse_transactions::report_subtotal() +void collapse_xacts::report_subtotal() { assert(count >= 1); if (count == 1) { - item_handler::operator()(*last_xact); + item_handler::operator()(*last_xact); } else { entry_temps.push_back(entry_t()); entry_t& entry = entry_temps.back(); @@ -327,7 +327,7 @@ void collapse_transactions::report_subtotal() count = 0; } -void collapse_transactions::operator()(transaction_t& xact) +void collapse_xacts::operator()(xact_t& xact) { // If we've reached a new entry, report on the subtotal // accumulated thus far. @@ -335,61 +335,61 @@ void collapse_transactions::operator()(transaction_t& xact) if (last_entry && last_entry != xact.entry && count > 0) report_subtotal(); - add_transaction_to(xact, subtotal); + add_xact_to(xact, subtotal); count++; last_entry = xact.entry; last_xact = &xact; } -void related_transactions::flush() +void related_xacts::flush() { - if (transactions.size() > 0) { - for (transactions_list::iterator i = transactions.begin(); - i != transactions.end(); + if (xacts.size() > 0) { + for (xacts_list::iterator i = xacts.begin(); + i != xacts.end(); i++) { if ((*i)->entry) { - for (transactions_list::iterator j = (*i)->entry->transactions.begin(); - j != (*i)->entry->transactions.end(); + for (xacts_list::iterator j = (*i)->entry->xacts.begin(); + j != (*i)->entry->xacts.end(); j++) { - transaction_xdata_t& xdata = transaction_xdata(**j); - if (! (xdata.dflags & TRANSACTION_HANDLED) && - (! (xdata.dflags & TRANSACTION_RECEIVED) ? - ! (*j)->has_flags(TRANSACTION_AUTO | TRANSACTION_VIRTUAL) : + xact_xdata_t& xdata = xact_xdata(**j); + if (! (xdata.dflags & XACT_HANDLED) && + (! (xdata.dflags & XACT_RECEIVED) ? + ! (*j)->has_flags(XACT_AUTO | XACT_VIRTUAL) : also_matching)) { - xdata.dflags |= TRANSACTION_HANDLED; - item_handler::operator()(**j); + xdata.dflags |= XACT_HANDLED; + item_handler::operator()(**j); } } } else { // This code should only be reachable from the "output" // command, since that is the only command which attempts to // output auto or period entries. - transaction_xdata_t& xdata = transaction_xdata(**i); - if (! (xdata.dflags & TRANSACTION_HANDLED) && - ! (*i)->has_flags(TRANSACTION_AUTO)) { - xdata.dflags |= TRANSACTION_HANDLED; - item_handler::operator()(**i); + xact_xdata_t& xdata = xact_xdata(**i); + if (! (xdata.dflags & XACT_HANDLED) && + ! (*i)->has_flags(XACT_AUTO)) { + xdata.dflags |= XACT_HANDLED; + item_handler::operator()(**i); } } } } - item_handler::flush(); + item_handler::flush(); } -void changed_value_transactions::output_diff(const datetime_t& current) +void changed_value_xacts::output_diff(const datetime_t& current) { value_t cur_bal; - transaction_xdata(*last_xact).date = current; + xact_xdata(*last_xact).date = current; #if 0 compute_total(cur_bal, details_t(*last_xact)); #endif cur_bal.round(); // jww (2008-04-24): What does this do? #if 0 - transaction_xdata(*last_xact).date = 0; + xact_xdata(*last_xact).date = 0; #endif if (value_t diff = cur_bal - last_balance) { @@ -398,26 +398,26 @@ void changed_value_transactions::output_diff(const datetime_t& current) entry.payee = "Commodities revalued"; entry._date = current; - handle_value(diff, NULL, &entry, TRANSACTION_NO_TOTAL, xact_temps, + handle_value(diff, NULL, &entry, XACT_NO_TOTAL, xact_temps, *handler); } } -void changed_value_transactions::operator()(transaction_t& xact) +void changed_value_xacts::operator()(xact_t& xact) { if (last_xact) { datetime_t moment; - if (transaction_has_xdata(*last_xact)) - moment = transaction_xdata_(*last_xact).date; + if (xact_has_xdata(*last_xact)) + moment = xact_xdata_(*last_xact).date; else moment = xact.date(); output_diff(moment); } if (changed_values_only) - transaction_xdata(xact).dflags |= TRANSACTION_DISPLAYED; + xact_xdata(xact).dflags |= XACT_DISPLAYED; - item_handler::operator()(xact); + item_handler::operator()(xact); #if 0 compute_total(last_balance, details_t(xact)); @@ -427,18 +427,18 @@ void changed_value_transactions::operator()(transaction_t& xact) last_xact = &xact; } -void component_transactions::operator()(transaction_t& xact) +void component_xacts::operator()(xact_t& xact) { if (handler && pred(xact)) { - if (transaction_has_xdata(xact) && - transaction_xdata_(xact).have_component_xacts()) - transaction_xdata_(xact).walk_component_xacts(*handler); + if (xact_has_xdata(xact) && + xact_xdata_(xact).have_component_xacts()) + xact_xdata_(xact).walk_component_xacts(*handler); else (*handler)(xact); } } -void subtotal_transactions::report_subtotal(const char * spec_fmt) +void subtotal_xacts::report_subtotal(const char * spec_fmt) { std::ostringstream out_date; if (! spec_fmt) { @@ -468,7 +468,7 @@ void subtotal_transactions::report_subtotal(const char * spec_fmt) values.clear(); } -void subtotal_transactions::operator()(transaction_t& xact) +void subtotal_xacts::operator()(xact_t& xact) { if (! is_valid(start) || xact.date() < start) start = xact.date(); @@ -481,7 +481,7 @@ void subtotal_transactions::operator()(transaction_t& xact) values_map::iterator i = values.find(acct->fullname()); if (i == values.end()) { value_t temp; - add_transaction_to(xact, temp); + add_xact_to(xact, temp); std::pair result = values.insert(values_pair(acct->fullname(), acct_value_t(acct, temp))); assert(result.second); @@ -489,23 +489,23 @@ void subtotal_transactions::operator()(transaction_t& xact) if (remember_components) (*result.first).second.components.push_back(&xact); } else { - add_transaction_to(xact, (*i).second.value); + add_xact_to(xact, (*i).second.value); if (remember_components) (*i).second.components.push_back(&xact); } - // If the account for this transaction is all virtual, mark it as + // If the account for this xact is all virtual, mark it as // such, so that `handle_value' can show "(Account)" for accounts - // that contain only virtual transactions. + // that contain only virtual xacts. - if (! xact.has_flags(TRANSACTION_VIRTUAL)) + if (! xact.has_flags(XACT_VIRTUAL)) account_xdata(*xact_account(xact)).dflags |= ACCOUNT_HAS_NON_VIRTUALS; - else if (! xact.has_flags(TRANSACTION_BALANCE)) + else if (! xact.has_flags(XACT_BALANCE)) account_xdata(*xact_account(xact)).dflags |= ACCOUNT_HAS_UNB_VIRTUALS; } -void interval_transactions::report_subtotal(const datetime_t& moment) +void interval_xacts::report_subtotal(const datetime_t& moment) { assert(last_xact); @@ -520,12 +520,12 @@ void interval_transactions::report_subtotal(const datetime_t& moment) else finish = last_xact->date(); - subtotal_transactions::report_subtotal(); + subtotal_xacts::report_subtotal(); last_xact = NULL; } -void interval_transactions::operator()(transaction_t& xact) +void interval_xacts::operator()(xact_t& xact) { const datetime_t date = xact.date(); @@ -555,17 +555,17 @@ void interval_transactions::operator()(transaction_t& xact) start = interval.begin = quant; } - subtotal_transactions::operator()(xact); + subtotal_xacts::operator()(xact); } else { - item_handler::operator()(xact); + item_handler::operator()(xact); } last_xact = &xact; } -by_payee_transactions::~by_payee_transactions() +by_payee_xacts::~by_payee_xacts() { - TRACE_DTOR(by_payee_transactions); + TRACE_DTOR(by_payee_xacts); for (payee_subtotals_map::iterator i = payee_subtotals.begin(); i != payee_subtotals.end(); @@ -573,25 +573,25 @@ by_payee_transactions::~by_payee_transactions() checked_delete((*i).second); } -void by_payee_transactions::flush() +void by_payee_xacts::flush() { for (payee_subtotals_map::iterator i = payee_subtotals.begin(); i != payee_subtotals.end(); i++) (*i).second->report_subtotal((*i).first.c_str()); - item_handler::flush(); + item_handler::flush(); payee_subtotals.clear(); } -void by_payee_transactions::operator()(transaction_t& xact) +void by_payee_xacts::operator()(xact_t& xact) { payee_subtotals_map::iterator i = payee_subtotals.find(xact.entry->payee); if (i == payee_subtotals.end()) { payee_subtotals_pair temp(xact.entry->payee, - new subtotal_transactions(handler, remember_components)); + new subtotal_xacts(handler, remember_components)); std::pair result = payee_subtotals.insert(temp); @@ -607,7 +607,7 @@ void by_payee_transactions::operator()(transaction_t& xact) (*(*i).second)(xact); } -void set_comm_as_payee::operator()(transaction_t& xact) +void set_comm_as_payee::operator()(xact_t& xact) { entry_temps.push_back(*xact.entry); entry_t& entry = entry_temps.back(); @@ -620,17 +620,17 @@ void set_comm_as_payee::operator()(transaction_t& xact) entry.payee = ""; xact_temps.push_back(xact); - transaction_t& temp = xact_temps.back(); + xact_t& temp = xact_temps.back(); temp.entry = &entry; temp.state = xact.state; - temp.add_flags(TRANSACTION_BULK_ALLOC); + temp.add_flags(XACT_BULK_ALLOC); - entry.add_transaction(&temp); + entry.add_xact(&temp); - item_handler::operator()(temp); + item_handler::operator()(temp); } -void set_code_as_payee::operator()(transaction_t& xact) +void set_code_as_payee::operator()(xact_t& xact) { entry_temps.push_back(*xact.entry); entry_t& entry = entry_temps.back(); @@ -642,53 +642,53 @@ void set_code_as_payee::operator()(transaction_t& xact) entry.payee = ""; xact_temps.push_back(xact); - transaction_t& temp = xact_temps.back(); + xact_t& temp = xact_temps.back(); temp.entry = &entry; temp.state = xact.state; - temp.add_flags(TRANSACTION_BULK_ALLOC); + temp.add_flags(XACT_BULK_ALLOC); - entry.add_transaction(&temp); + entry.add_xact(&temp); - item_handler::operator()(temp); + item_handler::operator()(temp); } -void dow_transactions::flush() +void dow_xacts::flush() { for (int i = 0; i < 7; i++) { // jww (2008-04-24): What to use here? #if 0 start = finish = 0; #endif - for (transactions_list::iterator d = days_of_the_week[i].begin(); + for (xacts_list::iterator d = days_of_the_week[i].begin(); d != days_of_the_week[i].end(); d++) - subtotal_transactions::operator()(**d); - subtotal_transactions::report_subtotal("%As"); + subtotal_xacts::operator()(**d); + subtotal_xacts::report_subtotal("%As"); days_of_the_week[i].clear(); } - subtotal_transactions::flush(); + subtotal_xacts::flush(); } -void generate_transactions::add_period_entries +void generate_xacts::add_period_entries (period_entries_list& period_entries) { for (period_entries_list::iterator i = period_entries.begin(); i != period_entries.end(); i++) - for (transactions_list::iterator j = (*i)->transactions.begin(); - j != (*i)->transactions.end(); + for (xacts_list::iterator j = (*i)->xacts.begin(); + j != (*i)->xacts.end(); j++) - add_transaction((*i)->period, **j); + add_xact((*i)->period, **j); } -void generate_transactions::add_transaction(const interval_t& period, - transaction_t& xact) +void generate_xacts::add_xact(const interval_t& period, + xact_t& xact) { pending_xacts.push_back(pending_xacts_pair(period, &xact)); } -void budget_transactions::report_budget_items(const datetime_t& moment) +void budget_xacts::report_budget_items(const datetime_t& moment) { if (pending_xacts.size() == 0) return; @@ -707,7 +707,7 @@ void budget_transactions::report_budget_items(const datetime_t& moment) if (begin < moment && (! is_valid((*i).first.end) || begin < (*i).first.end)) { - transaction_t& xact = *(*i).second; + xact_t& xact = *(*i).second; DEBUG("ledger.walk.budget", "Reporting budget for " << xact_account(xact)->fullname()); @@ -723,15 +723,15 @@ void budget_transactions::report_budget_items(const datetime_t& moment) entry._date = begin; xact_temps.push_back(xact); - transaction_t& temp = xact_temps.back(); + xact_t& temp = xact_temps.back(); temp.entry = &entry; - temp.add_flags(TRANSACTION_AUTO | TRANSACTION_BULK_ALLOC); + temp.add_flags(XACT_AUTO | XACT_BULK_ALLOC); temp.amount.negate(); - entry.add_transaction(&temp); + entry.add_xact(&temp); begin = (*i).first.increment(begin); - item_handler::operator()(temp); + item_handler::operator()(temp); reported = true; } @@ -739,7 +739,7 @@ void budget_transactions::report_budget_items(const datetime_t& moment) } while (reported); } -void budget_transactions::operator()(transaction_t& xact) +void budget_xacts::operator()(xact_t& xact) { bool xact_in_budget = false; @@ -751,10 +751,10 @@ void budget_transactions::operator()(transaction_t& xact) acct = acct->parent) { if (acct == xact_account(*(*i).second)) { xact_in_budget = true; - // Report the transaction as if it had occurred in the parent + // Report the xact as if it had occurred in the parent // account. if (xact_account(xact) != acct) - transaction_xdata(xact).account = acct; + xact_xdata(xact).account = acct; goto handle; } } @@ -762,17 +762,17 @@ void budget_transactions::operator()(transaction_t& xact) handle: if (xact_in_budget && flags & BUDGET_BUDGETED) { report_budget_items(xact.date()); - item_handler::operator()(xact); + item_handler::operator()(xact); } else if (! xact_in_budget && flags & BUDGET_UNBUDGETED) { - item_handler::operator()(xact); + item_handler::operator()(xact); } } -void forecast_transactions::add_transaction(const interval_t& period, - transaction_t& xact) +void forecast_xacts::add_xact(const interval_t& period, + xact_t& xact) { - generate_transactions::add_transaction(period, xact); + generate_xacts::add_xact(period, xact); interval_t& i = pending_xacts.back().first; if (! is_valid(i.begin)) { @@ -784,9 +784,9 @@ void forecast_transactions::add_transaction(const interval_t& period, } } -void forecast_transactions::flush() +void forecast_xacts::flush() { - transactions_list passed; + xacts_list passed; datetime_t last; while (pending_xacts.size() > 0) { @@ -805,7 +805,7 @@ void forecast_transactions::flush() continue; } - transaction_t& xact = *(*least).second; + xact_t& xact = *(*least).second; entry_temps.push_back(entry_t()); entry_t& entry = entry_temps.back(); @@ -813,10 +813,10 @@ void forecast_transactions::flush() entry._date = begin; xact_temps.push_back(xact); - transaction_t& temp = xact_temps.back(); + xact_t& temp = xact_temps.back(); temp.entry = &entry; - temp.add_flags(TRANSACTION_AUTO | TRANSACTION_BULK_ALLOC); - entry.add_transaction(&temp); + temp.add_flags(XACT_AUTO | XACT_BULK_ALLOC); + entry.add_xact(&temp); datetime_t next = (*least).first.increment(begin); // jww (2008-04-24): Does seconds() here give the total seconds? @@ -825,17 +825,17 @@ void forecast_transactions::flush() break; begin = next; - item_handler::operator()(temp); + item_handler::operator()(temp); - if (transaction_has_xdata(temp) && - transaction_xdata_(temp).dflags & TRANSACTION_MATCHES) { + if (xact_has_xdata(temp) && + xact_xdata_(temp).dflags & XACT_MATCHES) { if (! pred(temp)) break; last = temp.date(); passed.clear(); } else { bool found = false; - for (transactions_list::iterator i = passed.begin(); + for (xacts_list::iterator i = passed.begin(); i != passed.end(); i++) if (*i == &xact) { @@ -851,7 +851,7 @@ void forecast_transactions::flush() } } - item_handler::flush(); + item_handler::flush(); } template <> @@ -967,9 +967,9 @@ account_t * sorted_accounts_iterator::operator()() } void walk_commodities(commodity_pool_t::commodities_by_ident& commodities, - item_handler& handler) + item_handler& handler) { - std::list xact_temps; + std::list xact_temps; std::list entry_temps; std::list acct_temps; @@ -989,12 +989,12 @@ void walk_commodities(commodity_pool_t::commodities_by_ident& commodities, j++) { entry_temps.back()._date = (*j).first; - xact_temps.push_back(transaction_t(&acct_temps.back())); - transaction_t& temp = xact_temps.back(); + xact_temps.push_back(xact_t(&acct_temps.back())); + xact_t& temp = xact_temps.back(); temp.entry = &entry_temps.back(); temp.amount = (*j).second; - temp.add_flags(TRANSACTION_BULK_ALLOC); - entry_temps.back().add_transaction(&temp); + temp.add_flags(XACT_BULK_ALLOC); + entry_temps.back().add_xact(&temp); handler(xact_temps.back()); } @@ -1002,7 +1002,7 @@ void walk_commodities(commodity_pool_t::commodities_by_ident& commodities, handler.flush(); - clear_entries_transactions(entry_temps); + clear_entries_xacts(entry_temps); } void journals_iterator::reset(session_t& session) diff --git a/walk.h b/walk.h index 8d041f50..4f895786 100644 --- a/walk.h +++ b/walk.h @@ -2,6 +2,7 @@ #define _WALK_H #include "journal.h" +#include "account.h" namespace ledger { @@ -31,7 +32,7 @@ public: } }; -typedef shared_ptr > xact_handler_ptr; +typedef shared_ptr > xact_handler_ptr; template class compare_items @@ -70,27 +71,27 @@ bool compare_items::operator()(const T * left, const T * right) } template <> -bool compare_items::operator()(const transaction_t * left, - const transaction_t * right); +bool compare_items::operator()(const xact_t * left, + const xact_t * right); template <> bool compare_items::operator()(const account_t * left, const account_t * right); ////////////////////////////////////////////////////////////////////// // -// Transaction handlers +// Xact handlers // -#define TRANSACTION_RECEIVED 0x0001 -#define TRANSACTION_HANDLED 0x0002 -#define TRANSACTION_TO_DISPLAY 0x0004 -#define TRANSACTION_DISPLAYED 0x0008 -#define TRANSACTION_NO_TOTAL 0x0010 -#define TRANSACTION_SORT_CALC 0x0020 -#define TRANSACTION_COMPOUND 0x0040 -#define TRANSACTION_MATCHES 0x0080 +#define XACT_RECEIVED 0x0001 +#define XACT_HANDLED 0x0002 +#define XACT_TO_DISPLAY 0x0004 +#define XACT_DISPLAYED 0x0008 +#define XACT_NO_TOTAL 0x0010 +#define XACT_SORT_CALC 0x0020 +#define XACT_COMPOUND 0x0040 +#define XACT_MATCHES 0x0080 -struct transaction_xdata_t : public noncopyable +struct xact_xdata_t : public noncopyable { value_t total; value_t sort_value; @@ -101,22 +102,22 @@ struct transaction_xdata_t : public noncopyable account_t * account; void * ptr; - transactions_list * component_xacts; + xacts_list * component_xacts; - transaction_xdata_t() + xact_xdata_t() : index(0), dflags(0), account(NULL), ptr(NULL), component_xacts(NULL) { - TRACE_CTOR(transaction_xdata_t, ""); + TRACE_CTOR(xact_xdata_t, ""); } - ~transaction_xdata_t() { - TRACE_DTOR(transaction_xdata_t); + ~xact_xdata_t() { + TRACE_DTOR(xact_xdata_t); if (component_xacts) checked_delete(component_xacts); } - void remember_xact(transaction_t& xact) { + void remember_xact(xact_t& xact) { if (! component_xacts) - component_xacts = new transactions_list; + component_xacts = new xacts_list; component_xacts->push_back(&xact); } @@ -124,43 +125,43 @@ struct transaction_xdata_t : public noncopyable return component_xacts != NULL && ! component_xacts->empty(); } - void copy_component_xacts(transactions_list& xacts) { - for (transactions_list::const_iterator i = xacts.begin(); + void copy_component_xacts(xacts_list& xacts) { + for (xacts_list::const_iterator i = xacts.begin(); i != xacts.end(); i++) remember_xact(**i); } - void walk_component_xacts(item_handler& handler) const { - for (transactions_list::const_iterator i = component_xacts->begin(); + void walk_component_xacts(item_handler& handler) const { + for (xacts_list::const_iterator i = component_xacts->begin(); i != component_xacts->end(); i++) handler(**i); } }; -inline bool transaction_has_xdata(const transaction_t& xact) { +inline bool xact_has_xdata(const xact_t& xact) { return xact.data != NULL; } -inline transaction_xdata_t& transaction_xdata_(const transaction_t& xact) { - return *((transaction_xdata_t *) xact.data); +inline xact_xdata_t& xact_xdata_(const xact_t& xact) { + return *((xact_xdata_t *) xact.data); } -transaction_xdata_t& transaction_xdata(const transaction_t& xact); -void add_transaction_to(const transaction_t& xact, value_t& value); +xact_xdata_t& xact_xdata(const xact_t& xact); +void add_xact_to(const xact_t& xact, value_t& value); -inline account_t * xact_account(transaction_t& xact) { +inline account_t * xact_account(xact_t& xact) { if (xact.data) { - account_t * account = transaction_xdata(xact).account; + account_t * account = xact_xdata(xact).account; if (account) return account; } return xact.account; } -inline const account_t * xact_account(const transaction_t& xact) { - return xact_account(const_cast(xact)); +inline const account_t * xact_account(const xact_t& xact) { + return xact_account(const_cast(xact)); } ////////////////////////////////////////////////////////////////////// @@ -196,119 +197,119 @@ public: entry_t * operator()(); }; -class transactions_iterator : public noncopyable +class xacts_iterator : public noncopyable { public: - virtual transaction_t * operator()() = 0; + virtual xact_t * operator()() = 0; }; -class entry_transactions_iterator : public transactions_iterator +class entry_xacts_iterator : public xacts_iterator { - transactions_list::iterator xacts_i; - transactions_list::iterator xacts_end; + xacts_list::iterator xacts_i; + xacts_list::iterator xacts_end; bool xacts_uninitialized; public: - entry_transactions_iterator() : xacts_uninitialized(true) { - TRACE_CTOR(entry_transactions_iterator, ""); + entry_xacts_iterator() : xacts_uninitialized(true) { + TRACE_CTOR(entry_xacts_iterator, ""); } - entry_transactions_iterator(entry_t& entry) + entry_xacts_iterator(entry_t& entry) : xacts_uninitialized(true) { - TRACE_CTOR(entry_transactions_iterator, "entry_t&"); + TRACE_CTOR(entry_xacts_iterator, "entry_t&"); reset(entry); } - virtual ~entry_transactions_iterator() throw() { - TRACE_DTOR(entry_transactions_iterator); + virtual ~entry_xacts_iterator() throw() { + TRACE_DTOR(entry_xacts_iterator); } void reset(entry_t& entry) { - xacts_i = entry.transactions.begin(); - xacts_end = entry.transactions.end(); + xacts_i = entry.xacts.begin(); + xacts_end = entry.xacts.end(); xacts_uninitialized = false; } - virtual transaction_t * operator()() { + virtual xact_t * operator()() { if (xacts_i == xacts_end || xacts_uninitialized) return NULL; return *xacts_i++; } }; -class session_transactions_iterator : public transactions_iterator +class session_xacts_iterator : public xacts_iterator { entries_iterator entries; - entry_transactions_iterator xacts; + entry_xacts_iterator xacts; public: - session_transactions_iterator() { - TRACE_CTOR(session_transactions_iterator, ""); + session_xacts_iterator() { + TRACE_CTOR(session_xacts_iterator, ""); } - session_transactions_iterator(session_t& session) { - TRACE_CTOR(session_transactions_iterator, "session_t&"); + session_xacts_iterator(session_t& session) { + TRACE_CTOR(session_xacts_iterator, "session_t&"); reset(session); } - virtual ~session_transactions_iterator() throw() { - TRACE_DTOR(session_transactions_iterator); + virtual ~session_xacts_iterator() throw() { + TRACE_DTOR(session_xacts_iterator); } void reset(session_t& session); - virtual transaction_t * operator()(); + virtual xact_t * operator()(); }; ////////////////////////////////////////////////////////////////////// -class ignore_transactions : public item_handler +class ignore_xacts : public item_handler { public: - virtual void operator()(transaction_t& xact) {} + virtual void operator()(xact_t& xact) {} }; -class clear_transaction_xdata : public item_handler +class clear_xact_xdata : public item_handler { public: - virtual void operator()(transaction_t& xact) { + virtual void operator()(xact_t& xact) { if (xact.data) { - checked_delete((transaction_xdata_t *) xact.data); + checked_delete((xact_xdata_t *) xact.data); xact.data = NULL; } } }; -class pass_down_transactions : public item_handler +class pass_down_xacts : public item_handler { - pass_down_transactions(); + pass_down_xacts(); public: - pass_down_transactions(xact_handler_ptr handler, - transactions_iterator& iter) - : item_handler(handler) { - TRACE_CTOR(pass_down_transactions, - "xact_handler_ptr, transactions_iterator"); - for (transaction_t * xact = iter(); xact; xact = iter()) - item_handler::operator()(*xact); + pass_down_xacts(xact_handler_ptr handler, + xacts_iterator& iter) + : item_handler(handler) { + TRACE_CTOR(pass_down_xacts, + "xact_handler_ptr, xacts_iterator"); + for (xact_t * xact = iter(); xact; xact = iter()) + item_handler::operator()(*xact); } - virtual ~pass_down_transactions() { - TRACE_DTOR(pass_down_transactions); + virtual ~pass_down_xacts() { + TRACE_DTOR(pass_down_xacts); } }; -class truncate_entries : public item_handler +class truncate_entries : public item_handler { int head_count; int tail_count; - transactions_list xacts; + xacts_list xacts; truncate_entries(); public: truncate_entries(xact_handler_ptr handler, int _head_count, int _tail_count) - : item_handler(handler), + : item_handler(handler), head_count(_head_count), tail_count(_tail_count) { TRACE_CTOR(truncate_entries, "xact_handler_ptr, int, int"); } @@ -317,83 +318,83 @@ public: } virtual void flush(); - virtual void operator()(transaction_t& xact) { + virtual void operator()(xact_t& xact) { xacts.push_back(&xact); } }; -class set_account_value : public item_handler +class set_account_value : public item_handler { public: set_account_value(xact_handler_ptr handler = xact_handler_ptr()) - : item_handler(handler) {} + : item_handler(handler) {} - virtual void operator()(transaction_t& xact); + virtual void operator()(xact_t& xact); }; -class push_to_transactions_list : public item_handler +class push_to_xacts_list : public item_handler { - push_to_transactions_list(); + push_to_xacts_list(); public: - transactions_list& xact_list; + xacts_list& xact_list; - push_to_transactions_list(transactions_list& _xact_list) + push_to_xacts_list(xacts_list& _xact_list) : xact_list(_xact_list) { - TRACE_CTOR(push_to_transactions_list, "transactions_list&"); + TRACE_CTOR(push_to_xacts_list, "xacts_list&"); } - virtual ~push_to_transactions_list() { - TRACE_DTOR(push_to_transactions_list); + virtual ~push_to_xacts_list() { + TRACE_DTOR(push_to_xacts_list); } - virtual void operator()(transaction_t& xact) { + virtual void operator()(xact_t& xact) { xact_list.push_back(&xact); } }; -class sort_transactions : public item_handler +class sort_xacts : public item_handler { - typedef std::deque transactions_deque; + typedef std::deque xacts_deque; - transactions_deque transactions; + xacts_deque xacts; const expr_t sort_order; - sort_transactions(); + sort_xacts(); public: - sort_transactions(xact_handler_ptr handler, + sort_xacts(xact_handler_ptr handler, const expr_t& _sort_order) - : item_handler(handler), + : item_handler(handler), sort_order(_sort_order) { - TRACE_CTOR(sort_transactions, + TRACE_CTOR(sort_xacts, "xact_handler_ptr, const value_expr&"); } - sort_transactions(xact_handler_ptr handler, + sort_xacts(xact_handler_ptr handler, const string& _sort_order) - : item_handler(handler), + : item_handler(handler), sort_order(_sort_order) { - TRACE_CTOR(sort_transactions, + TRACE_CTOR(sort_xacts, "xact_handler_ptr, const string&"); } - virtual ~sort_transactions() { - TRACE_DTOR(sort_transactions); + virtual ~sort_xacts() { + TRACE_DTOR(sort_xacts); } virtual void post_accumulated_xacts(); virtual void flush() { post_accumulated_xacts(); - item_handler::flush(); + item_handler::flush(); } - virtual void operator()(transaction_t& xact) { - transactions.push_back(&xact); + virtual void operator()(xact_t& xact) { + xacts.push_back(&xact); } }; -class sort_entries : public item_handler +class sort_entries : public item_handler { - sort_transactions sorter; + sort_xacts sorter; entry_t * last_entry; sort_entries(); @@ -417,10 +418,10 @@ public: virtual void flush() { sorter.flush(); - item_handler::flush(); + item_handler::flush(); } - virtual void operator()(transaction_t& xact) { + virtual void operator()(xact_t& xact) { if (last_entry && xact.entry != last_entry) sorter.post_accumulated_xacts(); @@ -430,187 +431,187 @@ public: } }; -class filter_transactions : public item_handler +class filter_xacts : public item_handler { - item_predicate pred; + item_predicate pred; - filter_transactions(); + filter_xacts(); public: - filter_transactions(xact_handler_ptr handler, + filter_xacts(xact_handler_ptr handler, const expr_t& predicate) - : item_handler(handler), pred(predicate) { - TRACE_CTOR(filter_transactions, + : item_handler(handler), pred(predicate) { + TRACE_CTOR(filter_xacts, "xact_handler_ptr, const value_expr&"); } - filter_transactions(xact_handler_ptr handler, + filter_xacts(xact_handler_ptr handler, const string& predicate) - : item_handler(handler), pred(predicate) { - TRACE_CTOR(filter_transactions, + : item_handler(handler), pred(predicate) { + TRACE_CTOR(filter_xacts, "xact_handler_ptr, const string&"); } - virtual ~filter_transactions() { - TRACE_DTOR(filter_transactions); + virtual ~filter_xacts() { + TRACE_DTOR(filter_xacts); } - virtual void operator()(transaction_t& xact) { + virtual void operator()(xact_t& xact) { if (pred(xact)) { - transaction_xdata(xact).dflags |= TRANSACTION_MATCHES; + xact_xdata(xact).dflags |= XACT_MATCHES; (*handler)(xact); } } }; -class calc_transactions : public item_handler +class calc_xacts : public item_handler { - transaction_t * last_xact; + xact_t * last_xact; - calc_transactions(); + calc_xacts(); public: - calc_transactions(xact_handler_ptr handler) - : item_handler(handler), last_xact(NULL) { - TRACE_CTOR(calc_transactions, "xact_handler_ptr"); + calc_xacts(xact_handler_ptr handler) + : item_handler(handler), last_xact(NULL) { + TRACE_CTOR(calc_xacts, "xact_handler_ptr"); } - virtual ~calc_transactions() { - TRACE_DTOR(calc_transactions); + virtual ~calc_xacts() { + TRACE_DTOR(calc_xacts); } - virtual void operator()(transaction_t& xact); + virtual void operator()(xact_t& xact); }; -class invert_transactions : public item_handler +class invert_xacts : public item_handler { - invert_transactions(); + invert_xacts(); public: - invert_transactions(xact_handler_ptr handler) - : item_handler(handler) {} + invert_xacts(xact_handler_ptr handler) + : item_handler(handler) {} - virtual void operator()(transaction_t& xact); + virtual void operator()(xact_t& xact); }; -inline void clear_entries_transactions(std::list& entries_list) { +inline void clear_entries_xacts(std::list& entries_list) { for (std::list::iterator i = entries_list.begin(); i != entries_list.end(); i++) - (*i).transactions.clear(); + (*i).xacts.clear(); } -class collapse_transactions : public item_handler +class collapse_xacts : public item_handler { - value_t subtotal; - unsigned int count; - entry_t * last_entry; - transaction_t * last_xact; - account_t totals_account; + value_t subtotal; + unsigned int count; + entry_t * last_entry; + xact_t * last_xact; + account_t totals_account; std::list entry_temps; - std::list xact_temps; + std::list xact_temps; - collapse_transactions(); + collapse_xacts(); public: - collapse_transactions(xact_handler_ptr handler) - : item_handler(handler), count(0), + collapse_xacts(xact_handler_ptr handler) + : item_handler(handler), count(0), last_entry(NULL), last_xact(NULL), totals_account(NULL, "") { - TRACE_CTOR(collapse_transactions, "xact_handler_ptr"); + TRACE_CTOR(collapse_xacts, "xact_handler_ptr"); } - virtual ~collapse_transactions() { - TRACE_DTOR(collapse_transactions); - clear_entries_transactions(entry_temps); + virtual ~collapse_xacts() { + TRACE_DTOR(collapse_xacts); + clear_entries_xacts(entry_temps); } virtual void flush() { if (subtotal) report_subtotal(); - item_handler::flush(); + item_handler::flush(); } void report_subtotal(); - virtual void operator()(transaction_t& xact); + virtual void operator()(xact_t& xact); }; -class component_transactions : public item_handler +class component_xacts : public item_handler { - item_predicate pred; + item_predicate pred; - component_transactions(); + component_xacts(); public: - component_transactions(xact_handler_ptr handler, + component_xacts(xact_handler_ptr handler, const expr_t& predicate) - : item_handler(handler), pred(predicate) { - TRACE_CTOR(component_transactions, + : item_handler(handler), pred(predicate) { + TRACE_CTOR(component_xacts, "xact_handler_ptr, const value_expr&"); } - component_transactions(xact_handler_ptr handler, + component_xacts(xact_handler_ptr handler, const string& predicate) - : item_handler(handler), pred(predicate) { - TRACE_CTOR(component_transactions, + : item_handler(handler), pred(predicate) { + TRACE_CTOR(component_xacts, "xact_handler_ptr, const string&"); } - virtual ~component_transactions() throw() { - TRACE_DTOR(component_transactions); + virtual ~component_xacts() throw() { + TRACE_DTOR(component_xacts); } - virtual void operator()(transaction_t& xact); + virtual void operator()(xact_t& xact); }; -class related_transactions : public item_handler +class related_xacts : public item_handler { - transactions_list transactions; + xacts_list xacts; bool also_matching; - related_transactions(); + related_xacts(); public: - related_transactions(xact_handler_ptr handler, + related_xacts(xact_handler_ptr handler, const bool _also_matching = false) - : item_handler(handler), + : item_handler(handler), also_matching(_also_matching) { - TRACE_CTOR(related_transactions, + TRACE_CTOR(related_xacts, "xact_handler_ptr, const bool"); } - virtual ~related_transactions() throw() { - TRACE_DTOR(related_transactions); + virtual ~related_xacts() throw() { + TRACE_DTOR(related_xacts); } virtual void flush(); - virtual void operator()(transaction_t& xact) { - transaction_xdata(xact).dflags |= TRANSACTION_RECEIVED; - transactions.push_back(&xact); + virtual void operator()(xact_t& xact) { + xact_xdata(xact).dflags |= XACT_RECEIVED; + xacts.push_back(&xact); } }; -class changed_value_transactions : public item_handler +class changed_value_xacts : public item_handler { - // This filter requires that calc_transactions be used at some point + // This filter requires that calc_xacts be used at some point // later in the chain. bool changed_values_only; - transaction_t * last_xact; + xact_t * last_xact; value_t last_balance; std::list entry_temps; - std::list xact_temps; + std::list xact_temps; - changed_value_transactions(); + changed_value_xacts(); public: - changed_value_transactions(xact_handler_ptr handler, + changed_value_xacts(xact_handler_ptr handler, bool _changed_values_only) - : item_handler(handler), + : item_handler(handler), changed_values_only(_changed_values_only), last_xact(NULL) { - TRACE_CTOR(changed_value_transactions, + TRACE_CTOR(changed_value_xacts, "xact_handler_ptr, bool"); } - virtual ~changed_value_transactions() { - TRACE_DTOR(changed_value_transactions); - clear_entries_transactions(entry_temps); + virtual ~changed_value_xacts() { + TRACE_DTOR(changed_value_xacts); + clear_entries_xacts(entry_temps); } virtual void flush() { @@ -618,15 +619,15 @@ public: output_diff(current_moment); last_xact = NULL; } - item_handler::flush(); + item_handler::flush(); } void output_diff(const datetime_t& current); - virtual void operator()(transaction_t& xact); + virtual void operator()(xact_t& xact); }; -class subtotal_transactions : public item_handler +class subtotal_xacts : public item_handler { class acct_value_t { @@ -636,7 +637,7 @@ class subtotal_transactions : public item_handler account_t * account; value_t value; - transactions_list components; + xacts_list components; acct_value_t(account_t * a) : account(a) { TRACE_CTOR(acct_value_t, "acount_t *"); @@ -657,29 +658,29 @@ class subtotal_transactions : public item_handler typedef std::map values_map; typedef std::pair values_pair; - subtotal_transactions(); + subtotal_xacts(); protected: values_map values; bool remember_components; std::list entry_temps; - std::list xact_temps; + std::list xact_temps; public: datetime_t start; datetime_t finish; - subtotal_transactions(xact_handler_ptr handler, + subtotal_xacts(xact_handler_ptr handler, bool _remember_components = false) - : item_handler(handler), + : item_handler(handler), remember_components(_remember_components) { - TRACE_CTOR(subtotal_transactions, + TRACE_CTOR(subtotal_xacts, "xact_handler_ptr, bool"); } - virtual ~subtotal_transactions() { - TRACE_DTOR(subtotal_transactions); - clear_entries_transactions(entry_temps); + virtual ~subtotal_xacts() { + TRACE_DTOR(subtotal_xacts); + clear_entries_xacts(entry_temps); } void report_subtotal(const char * spec_fmt = NULL); @@ -687,9 +688,9 @@ public: virtual void flush() { if (values.size() > 0) report_subtotal(); - item_handler::flush(); + item_handler::flush(); } - virtual void operator()(transaction_t& xact); + virtual void operator()(xact_t& xact); }; class interval_expr_error : public error { @@ -700,33 +701,33 @@ class interval_expr_error : public error { virtual ~interval_expr_error() throw() {} }; -class interval_transactions : public subtotal_transactions +class interval_xacts : public subtotal_xacts { interval_t interval; - transaction_t * last_xact; + xact_t * last_xact; bool started; - interval_transactions(); + interval_xacts(); public: - interval_transactions(xact_handler_ptr _handler, + interval_xacts(xact_handler_ptr _handler, const interval_t& _interval, bool remember_components = false) - : subtotal_transactions(_handler, remember_components), + : subtotal_xacts(_handler, remember_components), interval(_interval), last_xact(NULL), started(false) { - TRACE_CTOR(interval_transactions, + TRACE_CTOR(interval_xacts, "xact_handler_ptr, const interval_t&, bool"); } - interval_transactions(xact_handler_ptr _handler, + interval_xacts(xact_handler_ptr _handler, const string& _interval, bool remember_components = false) - : subtotal_transactions(_handler, remember_components), + : subtotal_xacts(_handler, remember_components), interval(_interval), last_xact(NULL), started(false) { - TRACE_CTOR(interval_transactions, + TRACE_CTOR(interval_xacts, "xact_handler_ptr, const string&, bool"); } - virtual ~interval_transactions() throw() { - TRACE_DTOR(interval_transactions); + virtual ~interval_xacts() throw() { + TRACE_DTOR(interval_xacts); } void report_subtotal(const datetime_t& moment = datetime_t()); @@ -734,172 +735,172 @@ public: virtual void flush() { if (last_xact) report_subtotal(); - subtotal_transactions::flush(); + subtotal_xacts::flush(); } - virtual void operator()(transaction_t& xact); + virtual void operator()(xact_t& xact); }; -class by_payee_transactions : public item_handler +class by_payee_xacts : public item_handler { - typedef std::map payee_subtotals_map; - typedef std::pair payee_subtotals_pair; + typedef std::map payee_subtotals_map; + typedef std::pair payee_subtotals_pair; payee_subtotals_map payee_subtotals; bool remember_components; - by_payee_transactions(); + by_payee_xacts(); public: - by_payee_transactions(xact_handler_ptr handler, + by_payee_xacts(xact_handler_ptr handler, bool _remember_components = false) - : item_handler(handler), + : item_handler(handler), remember_components(_remember_components) { - TRACE_CTOR(by_payee_transactions, + TRACE_CTOR(by_payee_xacts, "xact_handler_ptr, bool"); } - virtual ~by_payee_transactions(); + virtual ~by_payee_xacts(); virtual void flush(); - virtual void operator()(transaction_t& xact); + virtual void operator()(xact_t& xact); }; -class set_comm_as_payee : public item_handler +class set_comm_as_payee : public item_handler { std::list entry_temps; - std::list xact_temps; + std::list xact_temps; set_comm_as_payee(); public: set_comm_as_payee(xact_handler_ptr handler) - : item_handler(handler) { + : item_handler(handler) { TRACE_CTOR(set_comm_as_payee, "xact_handler_ptr"); } virtual ~set_comm_as_payee() { TRACE_DTOR(set_comm_as_payee); - clear_entries_transactions(entry_temps); + clear_entries_xacts(entry_temps); } - virtual void operator()(transaction_t& xact); + virtual void operator()(xact_t& xact); }; -class set_code_as_payee : public item_handler +class set_code_as_payee : public item_handler { std::list entry_temps; - std::list xact_temps; + std::list xact_temps; set_code_as_payee(); public: set_code_as_payee(xact_handler_ptr handler) - : item_handler(handler) { + : item_handler(handler) { TRACE_CTOR(set_code_as_payee, "xact_handler_ptr"); } virtual ~set_code_as_payee() { TRACE_DTOR(set_code_as_payee); - clear_entries_transactions(entry_temps); + clear_entries_xacts(entry_temps); } - virtual void operator()(transaction_t& xact); + virtual void operator()(xact_t& xact); }; -class dow_transactions : public subtotal_transactions +class dow_xacts : public subtotal_xacts { - transactions_list days_of_the_week[7]; + xacts_list days_of_the_week[7]; - dow_transactions(); + dow_xacts(); public: - dow_transactions(xact_handler_ptr handler, + dow_xacts(xact_handler_ptr handler, bool remember_components = false) - : subtotal_transactions(handler, remember_components) { - TRACE_CTOR(dow_transactions, "xact_handler_ptr, bool"); + : subtotal_xacts(handler, remember_components) { + TRACE_CTOR(dow_xacts, "xact_handler_ptr, bool"); } - virtual ~dow_transactions() throw() { - TRACE_DTOR(dow_transactions); + virtual ~dow_xacts() throw() { + TRACE_DTOR(dow_xacts); } virtual void flush(); - virtual void operator()(transaction_t& xact) { + virtual void operator()(xact_t& xact) { days_of_the_week[xact.date().date().day_of_week()].push_back(&xact); } }; -class generate_transactions : public item_handler +class generate_xacts : public item_handler { - generate_transactions(); + generate_xacts(); protected: - typedef std::pair pending_xacts_pair; + typedef std::pair pending_xacts_pair; typedef std::list pending_xacts_list; pending_xacts_list pending_xacts; std::list entry_temps; - std::list xact_temps; + std::list xact_temps; public: - generate_transactions(xact_handler_ptr handler) - : item_handler(handler) { - TRACE_CTOR(dow_transactions, "xact_handler_ptr"); + generate_xacts(xact_handler_ptr handler) + : item_handler(handler) { + TRACE_CTOR(dow_xacts, "xact_handler_ptr"); } - virtual ~generate_transactions() { - TRACE_DTOR(generate_transactions); - clear_entries_transactions(entry_temps); + virtual ~generate_xacts() { + TRACE_DTOR(generate_xacts); + clear_entries_xacts(entry_temps); } void add_period_entries(period_entries_list& period_entries); - virtual void add_transaction(const interval_t& period, transaction_t& xact); + virtual void add_xact(const interval_t& period, xact_t& xact); }; #define BUDGET_NO_BUDGET 0x00 #define BUDGET_BUDGETED 0x01 #define BUDGET_UNBUDGETED 0x02 -class budget_transactions : public generate_transactions +class budget_xacts : public generate_xacts { unsigned short flags; - budget_transactions(); + budget_xacts(); public: - budget_transactions(xact_handler_ptr handler, + budget_xacts(xact_handler_ptr handler, unsigned long _flags = BUDGET_BUDGETED) - : generate_transactions(handler), flags(_flags) { - TRACE_CTOR(budget_transactions, + : generate_xacts(handler), flags(_flags) { + TRACE_CTOR(budget_xacts, "xact_handler_ptr, unsigned long"); } - virtual ~budget_transactions() throw() { - TRACE_DTOR(budget_transactions); + virtual ~budget_xacts() throw() { + TRACE_DTOR(budget_xacts); } void report_budget_items(const datetime_t& moment); - virtual void operator()(transaction_t& xact); + virtual void operator()(xact_t& xact); }; -class forecast_transactions : public generate_transactions +class forecast_xacts : public generate_xacts { - item_predicate pred; + item_predicate pred; public: - forecast_transactions(xact_handler_ptr handler, + forecast_xacts(xact_handler_ptr handler, const expr_t& predicate) - : generate_transactions(handler), pred(predicate) { - TRACE_CTOR(forecast_transactions, "xact_handler_ptr, const expr_t&"); + : generate_xacts(handler), pred(predicate) { + TRACE_CTOR(forecast_xacts, "xact_handler_ptr, const expr_t&"); } - forecast_transactions(xact_handler_ptr handler, + forecast_xacts(xact_handler_ptr handler, const string& predicate) - : generate_transactions(handler), pred(predicate) { - TRACE_CTOR(forecast_transactions, "xact_handler_ptr, const string&"); + : generate_xacts(handler), pred(predicate) { + TRACE_CTOR(forecast_xacts, "xact_handler_ptr, const string&"); } - virtual ~forecast_transactions() throw() { - TRACE_DTOR(forecast_transactions); + virtual ~forecast_xacts() throw() { + TRACE_DTOR(forecast_xacts); } - virtual void add_transaction(const interval_t& period, - transaction_t& xact); + virtual void add_xact(const interval_t& period, + xact_t& xact); virtual void flush(); }; @@ -920,8 +921,8 @@ struct account_xdata_t : public noncopyable value_t value; value_t total; value_t sort_value; - unsigned int count; // transactions counted toward amount - unsigned int total_count; // transactions counted toward total + unsigned int count; // xacts counted toward amount + unsigned int total_count; // xacts counted toward total unsigned int virtuals; unsigned short dflags; @@ -1047,7 +1048,7 @@ public: #if 0 inline void clear_journal_xdata(journal_t& journal) { - clear_transaction_xdata xact_cleaner; + clear_xact_xdata xact_cleaner; walk_entries(journal.entries, xact_cleaner); clear_account_xdata acct_cleaner; diff --git a/xact.cc b/xact.cc new file mode 100644 index 00000000..d5c16517 --- /dev/null +++ b/xact.cc @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2003-2008, 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 + * met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of New Artisans LLC nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "xact.h" +#include "journal.h" + +namespace ledger { + +bool xact_t::use_effective_date = false; + +xact_t::~xact_t() +{ + TRACE_DTOR(xact_t); +} + +datetime_t xact_t::actual_date() const +{ + if (! _date && entry) + return entry->actual_date(); + return *_date; +} + +datetime_t xact_t::effective_date() const +{ + if (! _date_eff && entry) + return entry->effective_date(); + return *_date_eff; +} + +namespace { + value_t get_amount(call_scope_t& scope) + { + xact_t& xact(downcast(*scope.parent)); + return xact.amount; + } +} + +expr_t::ptr_op_t xact_t::lookup(const string& name) +{ + switch (name[0]) { + case 'a': + if (name[1] == '\0' || name == "amount") + return WRAP_FUNCTOR(bind(get_amount, _1)); + break; + } + +#if 0 + return entry->lookup(name); +#else + return expr_t::ptr_op_t(); +#endif +} + +bool xact_t::valid() const +{ + if (! entry) { + DEBUG("ledger.validate", "xact_t: ! entry"); + return false; + } + + if (state != UNCLEARED && state != CLEARED && state != PENDING) { + DEBUG("ledger.validate", "xact_t: state is bad"); + return false; + } + + xacts_list::const_iterator i = + std::find(entry->xacts.begin(), + entry->xacts.end(), this); + if (i == entry->xacts.end()) { + DEBUG("ledger.validate", "xact_t: ! found"); + return false; + } + + if (! account) { + DEBUG("ledger.validate", "xact_t: ! account"); + return false; + } + + if (! amount.valid()) { + DEBUG("ledger.validate", "xact_t: ! amount.valid()"); + return false; + } + + if (cost && ! cost->valid()) { + DEBUG("ledger.validate", "xact_t: cost && ! cost->valid()"); + return false; + } + + if (flags() & ~0x003f) { + DEBUG("ledger.validate", "xact_t: flags are bad"); + return false; + } + + return true; +} + +xact_context::xact_context(const xact_t& _xact, const string& desc) throw() + : file_context("", 0, desc), xact(_xact) +{ + const paths_list& sources(xact.entry->journal->sources); + unsigned int x = 0; + for (paths_list::const_iterator i = sources.begin(); + i != sources.end(); + i++, x++) + if (x == xact.entry->src_idx) { + file = *i; + break; + } + line = xact.beg_line; +} + +} // namespace ledger diff --git a/xact.h b/xact.h new file mode 100644 index 00000000..62b4e40c --- /dev/null +++ b/xact.h @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2003-2008, 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 + * met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of New Artisans LLC nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _XACT_H +#define _XACT_H + +#include "utils.h" +#include "scope.h" + +namespace ledger { + +// These flags persist with the object +#define XACT_NORMAL 0x0000 +#define XACT_VIRTUAL 0x0001 +#define XACT_BALANCE 0x0002 +#define XACT_AUTO 0x0004 +#define XACT_BULK_ALLOC 0x0008 +#define XACT_CALCULATED 0x0010 +#define XACT_GENERATED 0x0020 + +class entry_t; +class account_t; + +class xact_t : public supports_flags<>, public scope_t +{ + public: + enum state_t { UNCLEARED, CLEARED, PENDING }; + + entry_t * entry; + state_t state; + account_t * account; + optional _date; + optional _date_eff; + amount_t amount; + optional amount_expr; + optional cost; + optional cost_expr; + optional note; + istream_pos_type beg_pos; + unsigned long beg_line; + istream_pos_type end_pos; + unsigned long end_line; + + mutable void * data; + static bool use_effective_date; + + xact_t(account_t * _account = NULL, + flags_t _flags = XACT_NORMAL) + : supports_flags<>(_flags), entry(NULL), + state(UNCLEARED), account(_account), + beg_pos(0), beg_line(0), end_pos(0), end_line(0), data(NULL) + { + TRACE_CTOR(xact_t, "account_t *, flags_t"); + } + xact_t(account_t * _account, + const amount_t& _amount, + flags_t _flags = XACT_NORMAL, + const optional& _note = none) + : supports_flags<>(_flags), entry(NULL), state(UNCLEARED), + account(_account), amount(_amount), note(_note), + beg_pos(0), beg_line(0), end_pos(0), end_line(0), data(NULL) + { + TRACE_CTOR(xact_t, + "account_t *, const amount_t&, flags_t, const string&"); + } + xact_t(const xact_t& xact) + : supports_flags<>(xact), + entry(xact.entry), + state(xact.state), + account(xact.account), + _date(xact._date), + _date_eff(xact._date_eff), + amount(xact.amount), + cost(xact.cost), + note(xact.note), + beg_pos(xact.beg_pos), + beg_line(xact.beg_line), + end_pos(xact.end_pos), + end_line(xact.end_line), + data(xact.data) // jww (2008-07-19): What are the copy semantics? + { + TRACE_CTOR(xact_t, "copy"); + } + ~xact_t(); + + datetime_t actual_date() const; + datetime_t effective_date() const; + datetime_t date() const { + if (use_effective_date) + return effective_date(); + else + return actual_date(); + } + + bool must_balance() const { + return ! has_flags(XACT_VIRTUAL) || has_flags(XACT_BALANCE); + } + + virtual expr_t::ptr_op_t lookup(const string& name); + + bool valid() const; +}; + +class xact_context : public file_context { + public: + const xact_t& xact; + + xact_context(const xact_t& _xact, + const string& desc = "") throw(); + virtual ~xact_context() throw() {} +}; + +} // namespace ledger + +#endif // _XACT_H diff --git a/xml.cc b/xml.cc index e6aaebca..562dcf7e 100644 --- a/xml.cc +++ b/xml.cc @@ -14,7 +14,7 @@ static entry_t * curr_entry; static commodity_t * curr_comm; static string comm_flags; -static transaction_t::state_t curr_state; +static xact_t::state_t curr_state; static string data; static bool ignore; @@ -28,13 +28,13 @@ static void startElement(void *userData, const char *name, const char **attrs) if (std::strcmp(name, "entry") == 0) { assert(! curr_entry); curr_entry = new entry_t; - curr_state = transaction_t::UNCLEARED; + curr_state = xact_t::UNCLEARED; } - else if (std::strcmp(name, "transaction") == 0) { + else if (std::strcmp(name, "xact") == 0) { assert(curr_entry); - curr_entry->add_transaction(new transaction_t); - if (curr_state != transaction_t::UNCLEARED) - curr_entry->transactions.back()->state = curr_state; + curr_entry->add_xact(new xact_t); + if (curr_state != xact_t::UNCLEARED) + curr_entry->xacts.back()->state = curr_state; } else if (std::strcmp(name, "commodity") == 0) { if (string(attrs[0]) == "flags") @@ -59,7 +59,7 @@ static void endElement(void *userData, const char *name) count++; } else { account_t * acct = curr_journal->find_account(""); - curr_entry->add_transaction(new transaction_t(acct)); + curr_entry->add_xact(new xact_t(acct)); if (curr_journal->add_entry(curr_entry)) { count++; } else { @@ -79,28 +79,28 @@ static void endElement(void *userData, const char *name) curr_entry->code = data; } else if (std::strcmp(name, "en:cleared") == 0) { - curr_state = transaction_t::CLEARED; + curr_state = xact_t::CLEARED; } else if (std::strcmp(name, "en:pending") == 0) { - curr_state = transaction_t::PENDING; + curr_state = xact_t::PENDING; } else if (std::strcmp(name, "en:payee") == 0) { curr_entry->payee = data; } else if (std::strcmp(name, "tr:account") == 0) { - curr_entry->transactions.back()->account = curr_journal->find_account(data); + curr_entry->xacts.back()->account = curr_journal->find_account(data); } else if (std::strcmp(name, "tr:cleared") == 0) { - curr_entry->transactions.back()->state = transaction_t::CLEARED; + curr_entry->xacts.back()->state = xact_t::CLEARED; } else if (std::strcmp(name, "tr:pending") == 0) { - curr_entry->transactions.back()->state = transaction_t::PENDING; + curr_entry->xacts.back()->state = xact_t::PENDING; } else if (std::strcmp(name, "tr:virtual") == 0) { - curr_entry->transactions.back()->add_flags(TRANSACTION_VIRTUAL); + curr_entry->xacts.back()->add_flags(XACT_VIRTUAL); } else if (std::strcmp(name, "tr:generated") == 0) { - curr_entry->transactions.back()->add_flags(TRANSACTION_AUTO); + curr_entry->xacts.back()->add_flags(XACT_AUTO); } else if (std::strcmp(name, "symbol") == 0) { assert(! curr_comm); @@ -133,7 +133,7 @@ static void endElement(void *userData, const char *name) } #endif else if (std::strcmp(name, "quantity") == 0) { - curr_entry->transactions.back()->amount.parse(data); + curr_entry->xacts.back()->amount.parse(data); if (curr_comm) { string::size_type i = data.find('.'); if (i != string::npos) { @@ -141,7 +141,7 @@ static void endElement(void *userData, const char *name) if (precision > curr_comm->precision()) curr_comm->set_precision(precision); } - curr_entry->transactions.back()->amount.set_commodity(*curr_comm); + curr_entry->xacts.back()->amount.set_commodity(*curr_comm); curr_comm = NULL; } } @@ -383,17 +383,17 @@ void format_xml_entries::format_last_entry() } bool first = true; - for (transactions_list::const_iterator i = last_entry->transactions.begin(); - i != last_entry->transactions.end(); + for (xacts_list::const_iterator i = last_entry->xacts.begin(); + i != last_entry->xacts.end(); i++) { - if (transaction_has_xdata(**i) && - transaction_xdata_(**i).dflags & TRANSACTION_TO_DISPLAY) { + if (xact_has_xdata(**i) && + xact_xdata_(**i).dflags & XACT_TO_DISPLAY) { if (first) { - output_stream << " \n"; + output_stream << " \n"; first = false; } - output_stream << " \n"; + output_stream << " \n"; #if 0 // jww (2008-05-08): Need to format these @@ -408,14 +408,14 @@ void format_xml_entries::format_last_entry() << "\n"; #endif - if ((*i)->state == transaction_t::CLEARED) + if ((*i)->state == xact_t::CLEARED) output_stream << " \n"; - else if ((*i)->state == transaction_t::PENDING) + else if ((*i)->state == xact_t::PENDING) output_stream << " \n"; - if ((*i)->has_flags(TRANSACTION_VIRTUAL)) + if ((*i)->has_flags(XACT_VIRTUAL)) output_stream << " \n"; - if ((*i)->has_flags(TRANSACTION_AUTO)) + if ((*i)->has_flags(XACT_AUTO)) output_stream << " \n"; if ((*i)->account) { @@ -431,9 +431,9 @@ void format_xml_entries::format_last_entry() } output_stream << " \n"; - if (transaction_xdata_(**i).dflags & TRANSACTION_COMPOUND) + if (xact_xdata_(**i).dflags & XACT_COMPOUND) xml_write_value(output_stream, - transaction_xdata_(**i).value, 10); + xact_xdata_(**i).value, 10); else xml_write_value(output_stream, value_t((*i)->amount), 10); output_stream << " \n"; @@ -452,18 +452,18 @@ void format_xml_entries::format_last_entry() if (show_totals) { output_stream << " \n"; - xml_write_value(output_stream, transaction_xdata_(**i).total, 10); + xml_write_value(output_stream, xact_xdata_(**i).total, 10); output_stream << " \n"; } - output_stream << " \n"; + output_stream << " \n"; - transaction_xdata_(**i).dflags |= TRANSACTION_DISPLAYED; + xact_xdata_(**i).dflags |= XACT_DISPLAYED; } } if (! first) - output_stream << " \n"; + output_stream << " \n"; output_stream << " \n"; } -- cgit v1.2.3