summaryrefslogtreecommitdiff
path: root/journal.cc
diff options
context:
space:
mode:
authorJohn Wiegley <johnw@newartisans.com>2004-08-27 23:38:39 -0400
committerJohn Wiegley <johnw@newartisans.com>2004-08-27 23:38:39 -0400
commit16841fbae3adcb0a143d709e2597ce543bff084e (patch)
tree9683e8e1b4442b99e2d7f2e26cf409c89c0f10a6 /journal.cc
parentf0238fdd065ace9edbb65a45875f2f47a7a932d6 (diff)
downloadfork-ledger-16841fbae3adcb0a143d709e2597ce543bff084e.tar.gz
fork-ledger-16841fbae3adcb0a143d709e2597ce543bff084e.tar.bz2
fork-ledger-16841fbae3adcb0a143d709e2597ce543bff084e.zip
added (disabled) code for Boost.Python
Diffstat (limited to 'journal.cc')
-rw-r--r--journal.cc546
1 files changed, 546 insertions, 0 deletions
diff --git a/journal.cc b/journal.cc
new file mode 100644
index 00000000..3d2f60bd
--- /dev/null
+++ b/journal.cc
@@ -0,0 +1,546 @@
+#include "ledger.h"
+#include "valexpr.h"
+#include "datetime.h"
+#include "acconf.h"
+
+#include <fstream>
+
+namespace ledger {
+
+const std::string version = PACKAGE_VERSION;
+
+bool transaction_t::valid() const
+{
+ if (! entry)
+ return false;
+
+ bool found = false;
+ for (transactions_list::const_iterator i = entry->transactions.begin();
+ i != entry->transactions.end();
+ i++)
+ if (*i == this) {
+ found = true;
+ break;
+ }
+ if (! found)
+ return false;
+
+ if (! account)
+ return false;
+
+ found = false;
+ for (transactions_list::const_iterator i = account->transactions.begin();
+ i != account->transactions.end();
+ i++)
+ if (*i == this) {
+ found = true;
+ break;
+ }
+ if (! found)
+ return false;
+
+ if (! amount.valid())
+ return false;
+
+ if (cost && ! cost->valid())
+ return false;
+
+ if (flags & ~0x000f)
+ return false;
+
+ return true;
+}
+
+void entry_t::add_transaction(transaction_t * xact)
+{
+ xact->entry = this;
+ transactions.push_back(xact);
+ xact->account->add_transaction(xact);
+}
+
+bool entry_t::remove_transaction(transaction_t * xact)
+{
+ bool found = false;
+ transactions_list::iterator i;
+ for (i = transactions.begin(); i != transactions.end(); i++)
+ if (*i == xact) {
+ found = true;
+ break;
+ }
+ if (! found)
+ return false;
+
+ transactions.erase(i);
+
+ for (i = xact->account->transactions.begin();
+ i != xact->account->transactions.end();
+ i++)
+ if (*i == xact) {
+ xact->account->transactions.erase(i);
+ return true;
+ }
+
+ return false;
+}
+
+bool entry_t::valid() const
+{
+ if (! date || date == -1)
+ return false;
+
+ if (state != UNCLEARED && state != CLEARED && state != PENDING)
+ return false;
+
+ for (transactions_list::const_iterator i = transactions.begin();
+ i != transactions.end();
+ i++)
+ if ((*i)->entry != this || ! (*i)->valid())
+ return false;
+
+ return true;
+}
+
+account_t::~account_t()
+{
+ DEBUG_PRINT("ledger.memory.ctors", "dtor account_t");
+ //assert(! data);
+
+ for (accounts_map::iterator i = accounts.begin();
+ i != accounts.end();
+ i++)
+ delete (*i).second;
+}
+
+account_t * account_t::find_account(const std::string& name,
+ const bool auto_create)
+{
+ accounts_map::const_iterator i = accounts.find(name);
+ if (i != accounts.end())
+ return (*i).second;
+
+ static char buf[256];
+
+ std::string::size_type sep = name.find(':');
+ const char * first, * rest;
+ if (sep == std::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);
+ accounts.insert(accounts_pair(first, account));
+ } else {
+ account = (*i).second;
+ }
+
+ if (rest)
+ account = account->find_account(rest, auto_create);
+
+ return account;
+}
+
+bool account_t::remove_transaction(transaction_t * xact)
+{
+ for (transactions_list::iterator i = transactions.begin();
+ i != transactions.end();
+ i++)
+ if (*i == xact) {
+ transactions.erase(i);
+ return true;
+ }
+
+ return false;
+}
+
+std::string account_t::fullname() const
+{
+ if (! _fullname.empty()) {
+ return _fullname;
+ } else {
+ const account_t * first = this;
+ std::string fullname = name;
+
+ while (first->parent) {
+ first = first->parent;
+ if (! first->name.empty())
+ fullname = first->name + ":" + fullname;
+ }
+
+ _fullname = fullname;
+
+ return fullname;
+ }
+}
+
+bool account_t::valid() const
+{
+ if (name.find('-') != std::string::npos)
+ return false;
+
+ if (depth > 16)
+ return false;
+
+ for (transactions_list::const_iterator i = transactions.begin();
+ i != transactions.end();
+ i++)
+ if ((*i)->account != this)
+ return false;
+
+ for (accounts_map::const_iterator i = accounts.begin();
+ i != accounts.end();
+ i++)
+ if (! (*i).second->valid())
+ return false;
+
+ return true;
+}
+
+void clean_commodity_history(char * item_pool, char * item_pool_end);
+
+journal_t::~journal_t()
+{
+ DEBUG_PRINT("ledger.memory.dtors", "dtor journal_t");
+
+ delete master;
+
+ // Don't bother unhooking each entry's transactions from the
+ // accounts they refer to, because all accounts are about to
+ // be deleted.
+ for (entries_list::iterator i = entries.begin();
+ i != entries.end();
+ i++)
+ if (! item_pool ||
+ ((char *) *i) < item_pool || ((char *) *i) >= item_pool_end)
+ delete *i;
+ else
+ (*i)->~entry_t();
+
+ // Remove historical prices which were allocated in the item_pool.
+ clean_commodity_history(item_pool, item_pool_end);
+
+ if (item_pool)
+ delete[] item_pool;
+}
+
+bool journal_t::add_entry(entry_t * entry)
+{
+ entries.push_back(entry);
+
+ for (transactions_list::const_iterator i = entry->transactions.begin();
+ i != entry->transactions.end();
+ i++) {
+ (*i)->account->add_transaction(*i);
+
+ if ((*i)->cost) {
+ assert((*i)->cost->commodity);
+ (*i)->amount.commodity->add_price(entry->date,
+ *(*i)->cost / (*i)->amount);
+ }
+ }
+
+ return true;
+}
+
+bool journal_t::remove_entry(entry_t * entry)
+{
+ bool found = false;
+ entries_list::iterator i;
+ for (i = entries.begin(); i != entries.end(); i++)
+ if (*i == entry) {
+ found = true;
+ break;
+ }
+ if (! found)
+ return false;
+
+ entries.erase(i);
+
+ for (transactions_list::const_iterator i
+ = entry->transactions.begin();
+ i != entry->transactions.end();
+ i++)
+ (*i)->account->remove_transaction(*i);
+
+ return true;
+}
+
+entry_t * journal_t::derive_entry(strings_list::iterator i,
+ strings_list::iterator end) const
+{
+ std::auto_ptr<entry_t> added(new entry_t);
+
+ entry_t * matching = NULL;
+
+ if (! parse_date((*i).c_str(), &added->date)) {
+ std::cerr << "Error: Bad entry date: " << *i << std::endl;
+ return false;
+ }
+ ++i;
+
+ if (i == end) {
+ std::cerr << "Error: Too few arguments to 'entry'." << std::endl;
+ return false;
+ }
+
+ mask_t regexp(*i++);
+
+ for (entries_list::const_reverse_iterator j = entries.rbegin();
+ j != entries.rend();
+ j++)
+ if (regexp.match((*j)->payee)) {
+ matching = *j;
+ break;
+ }
+
+ added->payee = matching ? matching->payee : regexp.pattern;
+
+ if (i == end) {
+ std::cerr << "Error: Too few arguments to 'entry'." << std::endl;
+ return false;
+ }
+
+ if ((*i)[0] == '-' || std::isdigit((*i)[0])) {
+ if (! matching) {
+ std::cerr << "Error: Missing account name for non-matching entry."
+ << std::endl;
+ return false;
+ }
+
+ transaction_t * m_xact, * xact, * first;
+ m_xact = matching->transactions.front();
+
+ amount_t amt(*i++);
+ first = xact = new transaction_t(m_xact->account, amt);
+ added->add_transaction(xact);
+
+ if (xact->amount.commodity->symbol.empty())
+ xact->amount.commodity = m_xact->amount.commodity;
+
+ m_xact = matching->transactions.back();
+
+ xact = new transaction_t(m_xact->account, - first->amount);
+ added->add_transaction(xact);
+
+ if (i != end && std::string(*i++) == "-from" && i != end)
+ if (account_t * acct = find_account(*i))
+ added->transactions.back()->account = acct;
+ } else {
+ while (std::string(*i) != "-from") {
+ mask_t acct_regex(*i++);
+
+ account_t * acct = NULL;
+ commodity_t * cmdty = NULL;
+
+ if (matching) {
+ for (transactions_list::iterator x
+ = matching->transactions.begin();
+ x != matching->transactions.end();
+ x++) {
+ if (acct_regex.match((*x)->account->fullname())) {
+ acct = (*x)->account;
+ cmdty = (*x)->amount.commodity;
+ break;
+ }
+ }
+ }
+
+ if (! acct)
+ acct = find_account(acct_regex.pattern);
+
+ if (! acct) {
+ std::cerr << "Error: Could not find account name '"
+ << acct_regex.pattern << "'." << std::endl;
+ return false;
+ }
+
+ if (i == end) {
+ std::cerr << "Error: Too few arguments to 'entry'." << std::endl;
+ return false;
+ }
+
+ amount_t amt(*i++);
+ transaction_t * xact = new transaction_t(acct, amt);
+ added->add_transaction(xact);
+
+ if (! xact->amount.commodity)
+ xact->amount.commodity = cmdty;
+ }
+
+ if (i != end && std::string(*i++) == "-from" && i != end) {
+ if (account_t * acct = find_account(*i++))
+ added->add_transaction(new transaction_t(acct));
+ } else {
+ if (! matching) {
+ std::cerr << "Error: Could not figure out the account to draw from."
+ << std::endl;
+ std::exit(1);
+ }
+ transaction_t * xact
+ = new transaction_t(matching->transactions.back()->account);
+ added->add_transaction(xact);
+ }
+ }
+
+ return added.release();
+}
+
+bool journal_t::valid() const
+{
+ if (! master->valid())
+ return false;
+
+ for (entries_list::const_iterator i = entries.begin();
+ i != entries.end();
+ i++)
+ if (! (*i)->valid())
+ return false;
+
+ for (commodities_map::const_iterator i = commodity_t::commodities.begin();
+ i != commodity_t::commodities.end();
+ i++)
+ if (! (*i).second->valid())
+ return false;
+
+ return true;
+}
+
+void initialize_amounts();
+void shutdown_amounts();
+
+void initialize_formats();
+void shutdown_formats();
+
+void initialize()
+{
+ initialize_amounts();
+ initialize_formats();
+}
+
+void shutdown()
+{
+ shutdown_amounts();
+ shutdown_formats();
+}
+
+} // namespace ledger
+
+#ifdef USE_BOOST_PYTHON
+
+#include <boost/python.hpp>
+#include <boost/python/suite/indexing/vector_indexing_suite.hpp>
+
+using namespace boost::python;
+using namespace ledger;
+
+BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(journal_find_account_overloads,
+ find_account, 1, 2)
+
+#if 0
+template <typename T>
+struct ptr_to_ref
+{
+ ptr_to_ref(T *) {}
+};
+#endif
+
+void export_journal()
+{
+ class_< transaction_t > ("Transaction")
+ .def(init<account_t *, amount_t, optional<unsigned int, std::string> >())
+
+ .def_readwrite("entry", &transaction_t::entry)
+ .def_readwrite("account", &transaction_t::account)
+ .def_readwrite("amount", &transaction_t::amount)
+ .def_readwrite("cost", &transaction_t::cost)
+ .def_readwrite("flags", &transaction_t::flags)
+ .def_readwrite("note", &transaction_t::note)
+ .def_readwrite("data", &transaction_t::data)
+
+ .def("valid", &transaction_t::valid)
+ ;
+
+ class_< transactions_list > ("TransactionsList")
+ .def(vector_indexing_suite< transactions_list >())
+ ;
+
+ class_< entry_t > ("Entry")
+ .def_readwrite("date", &entry_t::date)
+ .def_readwrite("state", &entry_t::state)
+ .def_readwrite("code", &entry_t::code)
+ .def_readwrite("payee", &entry_t::payee)
+ .def_readonly("transactions", &entry_t::transactions)
+
+ .def("add_transaction", &entry_t::add_transaction)
+ .def("remove_transaction", &entry_t::remove_transaction)
+
+ .def("valid", &entry_t::valid)
+ ;
+
+ class_< account_t >
+ ("Account", init<optional<account_t *, std::string, std::string> >())
+ .def_readwrite("parent", &account_t::parent)
+ .def_readwrite("name", &account_t::name)
+ .def_readwrite("note", &account_t::note)
+ .def_readonly("depth", &account_t::depth)
+ .def_readonly("transactions", &account_t::transactions)
+ .def_readwrite("data", &account_t::data)
+ .def_readonly("ident", &account_t::ident)
+
+#if 0
+ .def(str(self))
+#endif
+
+ .def("fullname", &account_t::fullname)
+ .def("add_account", &account_t::add_account)
+ .def("remove_account", &account_t::remove_account)
+ .def("find_account", &account_t::find_account,
+ return_value_policy<reference_existing_object>())
+ .def("add_transaction", &account_t::add_transaction)
+ .def("remove_transaction", &account_t::remove_transaction)
+
+ .def("valid", &account_t::valid)
+ ;
+
+ class_< entries_list > ("EntriesList")
+ .def(vector_indexing_suite< entries_list >())
+ ;
+
+ class_< strings_list > ("StringsList")
+ .def(vector_indexing_suite< strings_list >())
+ ;
+
+ class_< journal_t > ("Journal")
+ .def_readwrite("master", &journal_t::master)
+ .def_readonly("entries", &journal_t::entries)
+ .def_readwrite("sources", &journal_t::sources)
+
+ .def("add_account", &journal_t::add_account)
+ .def("remove_account", &journal_t::remove_account)
+#if 0
+ .def("find_account", &journal_t::find_account,
+ journal_find_account_overloads(args("name", "auto_create"))
+ [return_value_policy<reference_existing_object>()])
+#endif
+
+ .def("add_entry", &journal_t::add_entry)
+ .def("remove_entry", &journal_t::remove_entry)
+ .def("derive_entry", &journal_t::derive_entry,
+ return_value_policy<reference_existing_object>())
+
+ .def("valid", &journal_t::valid)
+ ;
+}
+
+#endif // USE_BOOST_PYTHON