diff options
author | John Wiegley <johnw@newartisans.com> | 2008-07-29 20:10:03 -0400 |
---|---|---|
committer | John Wiegley <johnw@newartisans.com> | 2008-07-29 20:10:03 -0400 |
commit | ea27d1b45a5ff975a1e90e3e9f4b74ff8d34056e (patch) | |
tree | 492a147199ad921959f86e8f0b4ec4edc1eeed46 | |
parent | 200d919fe7c8bcf021011c16fb6ec50821444d5e (diff) | |
download | fork-ledger-ea27d1b45a5ff975a1e90e3e9f4b74ff8d34056e.tar.gz fork-ledger-ea27d1b45a5ff975a1e90e3e9f4b74ff8d34056e.tar.bz2 fork-ledger-ea27d1b45a5ff975a1e90e3e9f4b74ff8d34056e.zip |
Moved around and renamed a very large amount of code in order to rationalize
the way that value expressions extract information from journal objects.
-rw-r--r-- | Makefile.am | 37 | ||||
-rw-r--r-- | account.cc | 141 | ||||
-rw-r--r-- | account.h | 103 | ||||
-rw-r--r-- | binary.cc | 72 | ||||
-rw-r--r-- | csv.cc | 18 | ||||
-rw-r--r-- | csv.h | 14 | ||||
-rw-r--r-- | derive.cc | 58 | ||||
-rw-r--r-- | emacs.cc | 14 | ||||
-rw-r--r-- | emacs.h | 14 | ||||
-rw-r--r-- | entry.cc | 451 | ||||
-rw-r--r-- | entry.h | 249 | ||||
-rw-r--r-- | expr.cc | 17 | ||||
-rw-r--r-- | expr.h | 28 | ||||
-rw-r--r-- | format.cc | 74 | ||||
-rw-r--r-- | format.h | 20 | ||||
-rw-r--r-- | gnucash.cc | 30 | ||||
-rw-r--r-- | hooks.h | 70 | ||||
-rw-r--r-- | journal.cc | 579 | ||||
-rw-r--r-- | journal.h | 436 | ||||
-rw-r--r-- | main.cc | 4 | ||||
-rw-r--r-- | main.py | 373 | ||||
-rw-r--r-- | ofx.cc | 20 | ||||
-rw-r--r-- | op.cc | 68 | ||||
-rw-r--r-- | option.cc | 2 | ||||
-rw-r--r-- | qif.cc | 24 | ||||
-rw-r--r-- | quotes.cc | 10 | ||||
-rw-r--r-- | quotes.h | 5 | ||||
-rw-r--r-- | reconcile.cc | 28 | ||||
-rw-r--r-- | reconcile.h | 20 | ||||
-rw-r--r-- | report.cc | 140 | ||||
-rw-r--r-- | report.h | 2 | ||||
-rw-r--r-- | scope.cc | 13 | ||||
-rw-r--r-- | scope.h | 2 | ||||
-rw-r--r-- | session.cc | 14 | ||||
-rw-r--r-- | session.h | 5 | ||||
-rwxr-xr-x | test.py | 22 | ||||
-rw-r--r-- | textual.cc | 151 | ||||
-rw-r--r-- | textual.h | 15 | ||||
-rw-r--r-- | walk.cc | 340 | ||||
-rw-r--r-- | walk.h | 549 | ||||
-rw-r--r-- | xact.cc | 140 | ||||
-rw-r--r-- | xact.h | 143 | ||||
-rw-r--r-- | xml.cc | 64 |
43 files changed, 2264 insertions, 2315 deletions
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<accounts_map::iterator, bool> 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<const string, account_t *> accounts_map; + +class account_t +{ + public: + typedef unsigned long ident_t; + + account_t * parent; + string name; + optional<string> 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<string>& _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 @@ -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<transaction_t::flags_t>(data)); - xact->add_flags(TRANSACTION_BULK_ALLOC); + xact->set_flags(read_number<xact_t::flags_t>(data)); + xact->add_flags(XACT_BULK_ALLOC); read_string(data, xact->note); xact->beg_pos = read_long<unsigned 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<unsigned 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<unsigned 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<transaction_t>(expr); + entry->predicate = item_predicate<xact_t>(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<unsigned char>(out, 0); write_amount(out, amount_t()); } else if (xact->amount_expr) { write_number<unsigned char>(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<unsigned char>(out, 1); write_amount(out, xact->amount); - write_string(out, xact->amount_expr.text()); + write_string(out, xact->amount_expr->text()); } else { write_number<unsigned char>(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<account_t::ident_t>(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<unsigned long>(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<unsigned long>(out, entries.size()); write_long<unsigned long>(out, auto_entries.size()); @@ -1126,7 +1126,7 @@ void journal_t::write(std::ostream& out) write_long<commodity_t::ident_t>(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 @@ -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; } } @@ -6,25 +6,25 @@ namespace ledger { -class format_csv_transactions : public item_handler<transaction_t> +class format_csv_xacts : public item_handler<xact_t> { - 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 @@ -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(); @@ -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; } } @@ -6,21 +6,21 @@ namespace ledger { -class format_emacs_transactions : public item_handler<transaction_t> +class format_emacs_xacts : public item_handler<xact_t> { - 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<entry_t *>(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<string>()); + + 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<xact_t *> 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<datetime_t> _date_eff; + optional<string> 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<xact_t> 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<bool (entry_t& entry, bool post)> 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<entry_t *> entries_list; +typedef std::list<auto_entry_t *> auto_entries_list; +typedef std::list<period_entry_t *> 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 @@ -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); @@ -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); }; @@ -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<transactions_list&>(entry_base.transactions), - formatter); + walk_xacts(const_cast<xacts_list&>(entry_base.xacts), formatter); formatter.flush(); - clear_transaction_xdata cleaner; - walk_transactions(const_cast<transactions_list&>(entry_base.transactions), - cleaner); + clear_xact_xdata cleaner; + walk_xacts(const_cast<xacts_list&>(entry_base.xacts), cleaner); #endif } @@ -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<transaction_t> +class format_xacts : public item_handler<xact_t> { 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, @@ -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 : "<gnucash>"; 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 <typename T> +class hooks_t : public boost::noncopyable +{ + std::list<T> 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 <typename Data> + bool run_hooks(Data& item, bool post) { + for (typename std::list<T>::const_iterator i = list.begin(); + i != list.end(); + i++) + if (! (*(*i))(item, post)) + return false; + return true; + } +}; + +#endif // _HOOKS_H @@ -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<entry_t *>(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<string>()); - - 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<accounts_map::iterator, bool> 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 @@ -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<datetime_t> _date; - optional<datetime_t> _date_eff; - amount_t amount; - expr_t amount_expr; - optional<amount_t> cost; - optional<expr_t> cost_expr; - optional<string> 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<string>& _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<transaction_t *> 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<datetime_t> _date_eff; - optional<string> 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 <typename T> class item_predicate; - -class auto_entry_t : public entry_base_t -{ -public: - item_predicate<transaction_t> 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<const string, account_t *> accounts_map; - -class account_t -{ - public: - typedef unsigned long ident_t; - - account_t * parent; - string name; - optional<string> 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<string>& _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<bool (entry_t& entry, bool post)> 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 <typename T> -void add_hook(std::list<T>& list, T obj, const bool prepend = false) { - if (prepend) - list.push_front(obj); - else - list.push_back(obj); -} - -template <typename T> -void remove_hook(std::list<T>& list, T obj) { - list.remove(obj); -} - -template <typename T, typename Data> -bool run_hooks(std::list<T>& list, Data& item, bool post) { - for (typename std::list<T>::const_iterator i = list.begin(); - i != list.end(); - i++) - if (! (*(*i))(item, post)) - return false; - return true; -} - - -typedef std::list<entry_t *> entries_list; -typedef std::list<auto_entry_t *> auto_entries_list; -typedef std::list<period_entry_t *> period_entries_list; -typedef std::list<path> paths_list; -typedef std::list<string> strings_list; +typedef std::list<path> 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_finalizer_t *> entry_finalize_hooks; + hooks_t<entry_finalizer_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_finalizer_t *>(entry_finalize_hooks, finalizer); + entry_finalize_hooks.add_hook(finalizer); } void remove_entry_finalizer(entry_finalizer_t * finalizer) { - remove_hook<entry_finalizer_t *>(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 @@ -51,8 +51,8 @@ namespace ledger { var_t<report_t> report(args, 0); var_t<std::ostream> 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 == "<all>": - 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! @@ -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 <Unknown>, since it is not specified. account = curr_journal->find_account("<Unknown>"); - 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. @@ -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) { @@ -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:") { @@ -42,17 +42,17 @@ unsigned int qif_parser_t::parse(std::istream& in, std::auto_ptr<entry_t> entry; std::auto_ptr<amount_t> 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; @@ -1,14 +1,9 @@ #include "quotes.h" -#include "datetime.h" -#include "error.h" -#include "debug.h" - -#include <fstream> -#include <cstdlib> -#include <cstdio> +#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 @@ -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<transaction_t>::operator()(*first); + item_handler<xact_t>::operator()(*first); - item_handler<transaction_t>::flush(); + item_handler<xact_t>::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<transaction_t> +class reconcile_xacts : public item_handler<xact_t> { 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<transaction_t>(handler), + : item_handler<xact_t>(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); } }; @@ -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<std::string> 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(); } } @@ -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); @@ -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; @@ -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, ""); } @@ -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() @@ -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 @@ -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<expr_t> 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<transaction_t> xact(new transaction_t(NULL)); + std::auto_ptr<xact_t> 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<expr_t> 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_entry_t>& 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<accounts_map::iterator, bool> 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<transaction_t>& 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); @@ -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<transaction_t>& 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 { @@ -8,25 +8,25 @@ namespace ledger { template <> -bool compare_items<transaction_t>::operator()(const transaction_t * left, - const transaction_t * right) +bool compare_items<xact_t>::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<transaction_t>::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<transaction_t>::operator()(**x); + item_handler<xact_t>::operator()(**x); } xacts.clear(); - item_handler<transaction_t>::flush(); + item_handler<xact_t>::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<transaction_t>::operator()(xact); + item_handler<xact_t>::operator()(xact); } -void sort_transactions::post_accumulated_xacts() +void sort_xacts::post_accumulated_xacts() { - std::stable_sort(transactions.begin(), transactions.end(), - compare_items<transaction_t>(sort_order)); + std::stable_sort(xacts.begin(), xacts.end(), + compare_items<xact_t>(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<transaction_t>::operator()(**i); + xact_xdata(**i).dflags &= ~XACT_SORT_CALC; + item_handler<xact_t>::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<transaction_t>::operator()(xact); + item_handler<xact_t>::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<transaction_t>::operator()(xact); + item_handler<xact_t>::operator()(xact); } @@ -242,35 +242,35 @@ void handle_value(const value_t& value, account_t * account, entry_t * entry, unsigned int flags, - std::list<transaction_t>& temps, - item_handler<transaction_t>& handler, + std::list<xact_t>& temps, + item_handler<xact_t>& 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<transaction_t>::operator()(*last_xact); + item_handler<xact_t>::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<transaction_t>::operator()(**j); + xdata.dflags |= XACT_HANDLED; + item_handler<xact_t>::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<transaction_t>::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<xact_t>::operator()(**i); } } } } - item_handler<transaction_t>::flush(); + item_handler<xact_t>::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<transaction_t>::operator()(xact); + item_handler<xact_t>::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<values_map::iterator, bool> 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<transaction_t>::operator()(xact); + item_handler<xact_t>::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<transaction_t>::flush(); + item_handler<xact_t>::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<payee_subtotals_map::iterator, bool> 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 = "<none>"; 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<transaction_t>::operator()(temp); + item_handler<xact_t>::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 = "<none>"; 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<transaction_t>::operator()(temp); + item_handler<xact_t>::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<transaction_t>::operator()(temp); + item_handler<xact_t>::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<transaction_t>::operator()(xact); + item_handler<xact_t>::operator()(xact); } else if (! xact_in_budget && flags & BUDGET_UNBUDGETED) { - item_handler<transaction_t>::operator()(xact); + item_handler<xact_t>::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<transaction_t>::operator()(temp); + item_handler<xact_t>::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<transaction_t>::flush(); + item_handler<xact_t>::flush(); } template <> @@ -967,9 +967,9 @@ account_t * sorted_accounts_iterator::operator()() } void walk_commodities(commodity_pool_t::commodities_by_ident& commodities, - item_handler<transaction_t>& handler) + item_handler<xact_t>& handler) { - std::list<transaction_t> xact_temps; + std::list<xact_t> xact_temps; std::list<entry_t> entry_temps; std::list<account_t> 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) @@ -2,6 +2,7 @@ #define _WALK_H #include "journal.h" +#include "account.h" namespace ledger { @@ -31,7 +32,7 @@ public: } }; -typedef shared_ptr<item_handler<transaction_t> > xact_handler_ptr; +typedef shared_ptr<item_handler<xact_t> > xact_handler_ptr; template <typename T> class compare_items @@ -70,27 +71,27 @@ bool compare_items<T>::operator()(const T * left, const T * right) } template <> -bool compare_items<transaction_t>::operator()(const transaction_t * left, - const transaction_t * right); +bool compare_items<xact_t>::operator()(const xact_t * left, + const xact_t * right); template <> bool compare_items<account_t>::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<transaction_t>& handler) const { - for (transactions_list::const_iterator i = component_xacts->begin(); + void walk_component_xacts(item_handler<xact_t>& 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<transaction_t&>(xact)); +inline const account_t * xact_account(const xact_t& xact) { + return xact_account(const_cast<xact_t&>(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<transaction_t> +class ignore_xacts : public item_handler<xact_t> { public: - virtual void operator()(transaction_t& xact) {} + virtual void operator()(xact_t& xact) {} }; -class clear_transaction_xdata : public item_handler<transaction_t> +class clear_xact_xdata : public item_handler<xact_t> { 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<transaction_t> +class pass_down_xacts : public item_handler<xact_t> { - pass_down_transactions(); + pass_down_xacts(); public: - pass_down_transactions(xact_handler_ptr handler, - transactions_iterator& iter) - : item_handler<transaction_t>(handler) { - TRACE_CTOR(pass_down_transactions, - "xact_handler_ptr, transactions_iterator"); - for (transaction_t * xact = iter(); xact; xact = iter()) - item_handler<transaction_t>::operator()(*xact); + pass_down_xacts(xact_handler_ptr handler, + xacts_iterator& iter) + : item_handler<xact_t>(handler) { + TRACE_CTOR(pass_down_xacts, + "xact_handler_ptr, xacts_iterator"); + for (xact_t * xact = iter(); xact; xact = iter()) + item_handler<xact_t>::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<transaction_t> +class truncate_entries : public item_handler<xact_t> { 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<transaction_t>(handler), + : item_handler<xact_t>(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<transaction_t> +class set_account_value : public item_handler<xact_t> { public: set_account_value(xact_handler_ptr handler = xact_handler_ptr()) - : item_handler<transaction_t>(handler) {} + : item_handler<xact_t>(handler) {} - virtual void operator()(transaction_t& xact); + virtual void operator()(xact_t& xact); }; -class push_to_transactions_list : public item_handler<transaction_t> +class push_to_xacts_list : public item_handler<xact_t> { - 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<transaction_t> +class sort_xacts : public item_handler<xact_t> { - typedef std::deque<transaction_t *> transactions_deque; + typedef std::deque<xact_t *> 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<transaction_t>(handler), + : item_handler<xact_t>(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<transaction_t>(handler), + : item_handler<xact_t>(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<transaction_t>::flush(); + item_handler<xact_t>::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<transaction_t> +class sort_entries : public item_handler<xact_t> { - sort_transactions sorter; + sort_xacts sorter; entry_t * last_entry; sort_entries(); @@ -417,10 +418,10 @@ public: virtual void flush() { sorter.flush(); - item_handler<transaction_t>::flush(); + item_handler<xact_t>::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<transaction_t> +class filter_xacts : public item_handler<xact_t> { - item_predicate<transaction_t> pred; + item_predicate<xact_t> pred; - filter_transactions(); + filter_xacts(); public: - filter_transactions(xact_handler_ptr handler, + filter_xacts(xact_handler_ptr handler, const expr_t& predicate) - : item_handler<transaction_t>(handler), pred(predicate) { - TRACE_CTOR(filter_transactions, + : item_handler<xact_t>(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<transaction_t>(handler), pred(predicate) { - TRACE_CTOR(filter_transactions, + : item_handler<xact_t>(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<transaction_t> +class calc_xacts : public item_handler<xact_t> { - transaction_t * last_xact; + xact_t * last_xact; - calc_transactions(); + calc_xacts(); public: - calc_transactions(xact_handler_ptr handler) - : item_handler<transaction_t>(handler), last_xact(NULL) { - TRACE_CTOR(calc_transactions, "xact_handler_ptr"); + calc_xacts(xact_handler_ptr handler) + : item_handler<xact_t>(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<transaction_t> +class invert_xacts : public item_handler<xact_t> { - invert_transactions(); + invert_xacts(); public: - invert_transactions(xact_handler_ptr handler) - : item_handler<transaction_t>(handler) {} + invert_xacts(xact_handler_ptr handler) + : item_handler<xact_t>(handler) {} - virtual void operator()(transaction_t& xact); + virtual void operator()(xact_t& xact); }; -inline void clear_entries_transactions(std::list<entry_t>& entries_list) { +inline void clear_entries_xacts(std::list<entry_t>& entries_list) { for (std::list<entry_t>::iterator i = entries_list.begin(); i != entries_list.end(); i++) - (*i).transactions.clear(); + (*i).xacts.clear(); } -class collapse_transactions : public item_handler<transaction_t> +class collapse_xacts : public item_handler<xact_t> { - 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_t> entry_temps; - std::list<transaction_t> xact_temps; + std::list<xact_t> xact_temps; - collapse_transactions(); + collapse_xacts(); public: - collapse_transactions(xact_handler_ptr handler) - : item_handler<transaction_t>(handler), count(0), + collapse_xacts(xact_handler_ptr handler) + : item_handler<xact_t>(handler), count(0), last_entry(NULL), last_xact(NULL), totals_account(NULL, "<Total>") { - 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<transaction_t>::flush(); + item_handler<xact_t>::flush(); } void report_subtotal(); - virtual void operator()(transaction_t& xact); + virtual void operator()(xact_t& xact); }; -class component_transactions : public item_handler<transaction_t> +class component_xacts : public item_handler<xact_t> { - item_predicate<transaction_t> pred; + item_predicate<xact_t> pred; - component_transactions(); + component_xacts(); public: - component_transactions(xact_handler_ptr handler, + component_xacts(xact_handler_ptr handler, const expr_t& predicate) - : item_handler<transaction_t>(handler), pred(predicate) { - TRACE_CTOR(component_transactions, + : item_handler<xact_t>(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<transaction_t>(handler), pred(predicate) { - TRACE_CTOR(component_transactions, + : item_handler<xact_t>(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<transaction_t> +class related_xacts : public item_handler<xact_t> { - 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<transaction_t>(handler), + : item_handler<xact_t>(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<transaction_t> +class changed_value_xacts : public item_handler<xact_t> { - // 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_t> entry_temps; - std::list<transaction_t> xact_temps; + std::list<xact_t> 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<transaction_t>(handler), + : item_handler<xact_t>(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<transaction_t>::flush(); + item_handler<xact_t>::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<transaction_t> +class subtotal_xacts : public item_handler<xact_t> { class acct_value_t { @@ -636,7 +637,7 @@ class subtotal_transactions : public item_handler<transaction_t> 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<transaction_t> typedef std::map<string, acct_value_t> values_map; typedef std::pair<string, acct_value_t> values_pair; - subtotal_transactions(); + subtotal_xacts(); protected: values_map values; bool remember_components; std::list<entry_t> entry_temps; - std::list<transaction_t> xact_temps; + std::list<xact_t> 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<transaction_t>(handler), + : item_handler<xact_t>(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<transaction_t>::flush(); + item_handler<xact_t>::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<transaction_t> +class by_payee_xacts : public item_handler<xact_t> { - typedef std::map<string, subtotal_transactions *> payee_subtotals_map; - typedef std::pair<string, subtotal_transactions *> payee_subtotals_pair; + typedef std::map<string, subtotal_xacts *> payee_subtotals_map; + typedef std::pair<string, subtotal_xacts *> 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<transaction_t>(handler), + : item_handler<xact_t>(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<transaction_t> +class set_comm_as_payee : public item_handler<xact_t> { std::list<entry_t> entry_temps; - std::list<transaction_t> xact_temps; + std::list<xact_t> xact_temps; set_comm_as_payee(); public: set_comm_as_payee(xact_handler_ptr handler) - : item_handler<transaction_t>(handler) { + : item_handler<xact_t>(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<transaction_t> +class set_code_as_payee : public item_handler<xact_t> { std::list<entry_t> entry_temps; - std::list<transaction_t> xact_temps; + std::list<xact_t> xact_temps; set_code_as_payee(); public: set_code_as_payee(xact_handler_ptr handler) - : item_handler<transaction_t>(handler) { + : item_handler<xact_t>(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<transaction_t> +class generate_xacts : public item_handler<xact_t> { - generate_transactions(); + generate_xacts(); protected: - typedef std::pair<interval_t, transaction_t *> pending_xacts_pair; + typedef std::pair<interval_t, xact_t *> pending_xacts_pair; typedef std::list<pending_xacts_pair> pending_xacts_list; pending_xacts_list pending_xacts; std::list<entry_t> entry_temps; - std::list<transaction_t> xact_temps; + std::list<xact_t> xact_temps; public: - generate_transactions(xact_handler_ptr handler) - : item_handler<transaction_t>(handler) { - TRACE_CTOR(dow_transactions, "xact_handler_ptr"); + generate_xacts(xact_handler_ptr handler) + : item_handler<xact_t>(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<transaction_t> pred; + item_predicate<xact_t> 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<xact_t>(*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 @@ -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<datetime_t> _date; + optional<datetime_t> _date_eff; + amount_t amount; + optional<expr_t> amount_expr; + optional<amount_t> cost; + optional<expr_t> cost_expr; + optional<string> 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<string>& _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 @@ -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("<Unknown>"); - 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 << " <en:transactions>\n"; + output_stream << " <en:xacts>\n"; first = false; } - output_stream << " <transaction>\n"; + output_stream << " <xact>\n"; #if 0 // jww (2008-05-08): Need to format these @@ -408,14 +408,14 @@ void format_xml_entries::format_last_entry() << "</tr:date_eff>\n"; #endif - if ((*i)->state == transaction_t::CLEARED) + if ((*i)->state == xact_t::CLEARED) output_stream << " <tr:cleared/>\n"; - else if ((*i)->state == transaction_t::PENDING) + else if ((*i)->state == xact_t::PENDING) output_stream << " <tr:pending/>\n"; - if ((*i)->has_flags(TRANSACTION_VIRTUAL)) + if ((*i)->has_flags(XACT_VIRTUAL)) output_stream << " <tr:virtual/>\n"; - if ((*i)->has_flags(TRANSACTION_AUTO)) + if ((*i)->has_flags(XACT_AUTO)) output_stream << " <tr:generated/>\n"; if ((*i)->account) { @@ -431,9 +431,9 @@ void format_xml_entries::format_last_entry() } output_stream << " <tr:amount>\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 << " </tr:amount>\n"; @@ -452,18 +452,18 @@ void format_xml_entries::format_last_entry() if (show_totals) { output_stream << " <total>\n"; - xml_write_value(output_stream, transaction_xdata_(**i).total, 10); + xml_write_value(output_stream, xact_xdata_(**i).total, 10); output_stream << " </total>\n"; } - output_stream << " </transaction>\n"; + output_stream << " </xact>\n"; - transaction_xdata_(**i).dflags |= TRANSACTION_DISPLAYED; + xact_xdata_(**i).dflags |= XACT_DISPLAYED; } } if (! first) - output_stream << " </en:transactions>\n"; + output_stream << " </en:xacts>\n"; output_stream << " </entry>\n"; } |