diff options
author | John Wiegley <johnw@newartisans.com> | 2004-08-27 23:38:39 -0400 |
---|---|---|
committer | John Wiegley <johnw@newartisans.com> | 2004-08-27 23:38:39 -0400 |
commit | 16841fbae3adcb0a143d709e2597ce543bff084e (patch) | |
tree | 9683e8e1b4442b99e2d7f2e26cf409c89c0f10a6 /journal.cc | |
parent | f0238fdd065ace9edbb65a45875f2f47a7a932d6 (diff) | |
download | fork-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.cc | 546 |
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 |