diff options
-rw-r--r-- | config.cc | 63 | ||||
-rw-r--r-- | config.h | 10 | ||||
-rw-r--r-- | format.cc | 9 | ||||
-rw-r--r-- | format.h | 32 | ||||
-rw-r--r-- | journal.cc | 123 | ||||
-rw-r--r-- | ledger.h | 67 | ||||
-rw-r--r-- | main.cc | 26 | ||||
-rwxr-xr-x | main.py | 14 | ||||
-rw-r--r-- | valexpr.cc | 51 | ||||
-rw-r--r-- | walk.cc | 147 | ||||
-rw-r--r-- | walk.h | 310 |
11 files changed, 396 insertions, 456 deletions
@@ -44,7 +44,6 @@ config_t::config_t() use_cache = false; cache_dirty = false; - sort_order = NULL; } static void @@ -168,25 +167,6 @@ void config_t::process_options(const std::string& command, } } - // Parse the sort_string - - if (! sort_order && ! sort_string.empty()) { - try { - std::istringstream stream(sort_string); - sort_order = parse_value_expr(stream); - if (stream.peek() != -1) { - throw value_expr_error(std::string("Unexpected character '") + - char(stream.peek()) + "'"); - } - else if (! sort_order) { - throw error("Failed to parse sort criteria!"); - } - } - catch (const value_expr_error& err) { - throw error(std::string("In sort criteria: ") + err.what()); - } - } - // Setup the values of %t and %T, used in format strings try { @@ -218,35 +198,6 @@ void config_t::process_options(const std::string& command, pricing_leeway, cache_dirty); - // Parse the interval specifier, if provided - - if (! report_interval && ! interval_text.empty()) { - try { - std::istringstream stream(interval_text); - - report_interval.parse(stream); - - if (report_interval.begin) { - if (! predicate.empty()) - predicate += "&"; - char buf[32]; - std::sprintf(buf, "d>=%lu", report_interval.begin); - predicate += buf; - } - - if (report_interval.end) { - if (! predicate.empty()) - predicate += "&"; - char buf[32]; - std::sprintf(buf, "d<%lu", report_interval.end); - predicate += buf; - } - } - catch (const interval_expr_error& err) { - throw error(std::string("In interval (-z) specifier: ") + err.what()); - } - } - if (format_t::date_format.empty() && ! date_format.empty()) format_t::date_format = date_format; @@ -557,11 +508,11 @@ OPT_BEGIN(related, "r") { } OPT_END(related); OPT_BEGIN(interval, "p:") { - config.interval_text = optarg; + config.report_interval = optarg; } OPT_END(interval); OPT_BEGIN(weekly, "W") { - config.interval_text = "weekly"; + config.report_interval = "weekly"; } OPT_END(weekly); OPT_BEGIN(dow, "") { @@ -569,11 +520,11 @@ OPT_BEGIN(dow, "") { } OPT_END(dow); OPT_BEGIN(monthly, "M") { - config.interval_text = "monthly"; + config.report_interval = "monthly"; } OPT_END(monthly); OPT_BEGIN(yearly, "Y") { - config.interval_text = "yearly"; + config.report_interval = "yearly"; } OPT_END(yearly); OPT_BEGIN(limit, "l:") { @@ -721,7 +672,7 @@ void export_config() .def_readwrite("account", &config_t::account) .def_readwrite("predicate", &config_t::predicate) .def_readwrite("display_predicate", &config_t::display_predicate) - .def_readwrite("interval_text", &config_t::interval_text) + .def_readwrite("report_interval", &config_t::report_interval) .def_readwrite("format_string", &config_t::format_string) .def_readwrite("date_format", &config_t::date_format) .def_readwrite("sort_string", &config_t::sort_string) @@ -741,12 +692,8 @@ void export_config() .def_readwrite("use_cache", &config_t::use_cache) .def_readwrite("cache_dirty", &config_t::cache_dirty) - .def_readwrite("report_interval", &config_t::report_interval) .def_readwrite("format", &config_t::format) .def_readwrite("nformat", &config_t::nformat) - .add_property("sort_order", - make_getter(&config_t::sort_order, - return_value_policy<reference_existing_object>())) .def("process_options", py_process_options) ; @@ -34,7 +34,7 @@ struct config_t std::string account; std::string predicate; std::string display_predicate; - std::string interval_text; + std::string report_interval; std::string format_string; std::string date_format; std::string sort_string; @@ -56,22 +56,14 @@ struct config_t bool use_cache; bool cache_dirty; - interval_t report_interval; format_t format; format_t nformat; - value_expr_t * sort_order; - config_t(); config_t(const config_t&) { assert(0); } - ~config_t() { - if (sort_order) - delete sort_order; - } - void process_options(const std::string& command, strings_list::iterator arg, strings_list::iterator args_end); @@ -21,7 +21,8 @@ std::string partial_account_name(const account_t& account) for (const account_t * acct = &account; acct && acct->parent; acct = acct->parent) { - if (acct->data && ACCT_DATA(acct)->dflags & ACCOUNT_DISPLAYED) + if (account_has_xdata(*acct) && + account_xdata(*acct).dflags & ACCOUNT_DISPLAYED) break; if (name.empty()) @@ -356,7 +357,8 @@ void format_t::format(std::ostream& out, const details_t& details) const for (const account_t * acct = details.account; acct; acct = acct->parent) - if (acct->data && ACCT_DATA(acct)->dflags & ACCOUNT_DISPLAYED) { + if (account_has_xdata(*acct) && + account_xdata(*acct).dflags & ACCOUNT_DISPLAYED) { if (elem->min_width > 0 || elem->max_width > 0) out.width(elem->min_width > elem->max_width ? elem->min_width : elem->max_width); @@ -412,7 +414,8 @@ bool format_account::display_account(const account_t& account, const item_predicate<account_t>& disp_pred) { // Never display an account that has already been displayed. - if (account.data && ACCT_DATA_(account)->dflags & ACCOUNT_DISPLAYED) + if (account_has_xdata(account) && + account_xdata(account).dflags & ACCOUNT_DISPLAYED) return false; // At this point, one of two possibilities exists: the account is a @@ -108,17 +108,15 @@ class format_transactions : public item_handler<transaction_t> } virtual void operator()(transaction_t& xact) { - if (! xact.data || - ! (XACT_DATA_(xact)->dflags & TRANSACTION_DISPLAYED)) { + if (! transaction_has_xdata(xact) || + ! (transaction_xdata(xact).dflags & TRANSACTION_DISPLAYED)) { if (last_entry != xact.entry) { first_line_format.format(output_stream, details_t(xact)); last_entry = xact.entry; } else { next_lines_format.format(output_stream, details_t(xact)); } - if (! xact.data) - xact.data = new transaction_data_t; - XACT_DATA_(xact)->dflags |= TRANSACTION_DISPLAYED; + transaction_xdata(xact).dflags |= TRANSACTION_DISPLAYED; } } }; @@ -155,14 +153,10 @@ class format_account : public item_handler<account_t> virtual void operator()(account_t& account) { if (display_account(account, disp_pred)) { if (! account.parent) { - if (! account.data) - account.data = new account_data_t; - ACCT_DATA_(account)->dflags |= ACCOUNT_TO_DISPLAY; + account_xdata(account).dflags |= ACCOUNT_TO_DISPLAY; } else { format.format(output_stream, details_t(account)); - if (! account.data) - account.data = new account_data_t; - ACCT_DATA_(account)->dflags |= ACCOUNT_DISPLAYED; + account_xdata(account).dflags |= ACCOUNT_DISPLAYED; } } } @@ -194,11 +188,11 @@ class format_equity : public item_handler<account_t> } virtual void flush() { + account_xdata_t xdata; + xdata.value = total; + xdata.value.negate(); account_t summary(NULL, "Equity:Opening Balances"); - std::auto_ptr<account_data_t> acct_data(new account_data_t); - summary.data = acct_data.get(); - ((account_data_t *) summary.data)->value = total; - ((account_data_t *) summary.data)->value.negate(); + summary.data = &xdata; next_lines_format.format(output_stream, details_t(summary)); output_stream.flush(); } @@ -206,11 +200,9 @@ class format_equity : public item_handler<account_t> virtual void operator()(account_t& account) { if (format_account::display_account(account, disp_pred)) { next_lines_format.format(output_stream, details_t(account)); - if (! account.data) - account.data = new account_data_t; - else - total += ACCT_DATA_(account)->value; - ACCT_DATA_(account)->dflags |= ACCOUNT_DISPLAYED; + if (account_has_xdata(account)) + total += account_xdata(account).value; + account_xdata(account).dflags |= ACCOUNT_DISPLAYED; } } }; @@ -51,6 +51,60 @@ bool transaction_t::valid() const return true; } +balance_pair_t& add_transaction_to(const transaction_t& xact, + balance_pair_t& bal_pair) +{ + if (xact.cost && ! bal_pair.cost) + bal_pair.cost = new balance_t(bal_pair.quantity); + + bal_pair.quantity += xact.amount; + + if (bal_pair.cost) + *bal_pair.cost += xact.cost ? *xact.cost : xact.amount; + + return bal_pair; +} + +value_t& add_transaction_to(const transaction_t& xact, value_t& value) +{ + switch (value.type) { + case value_t::BOOLEAN: + case value_t::INTEGER: + value.cast(value_t::AMOUNT); + + case value_t::AMOUNT: + if (xact.cost) { + value.cast(value_t::BALANCE_PAIR); + return add_transaction_to(xact, value); + } + else if (((amount_t *) value.data)->commodity() != + xact.amount.commodity()) { + value.cast(value_t::BALANCE); + return add_transaction_to(xact, value); + } + *((amount_t *) value.data) += xact.amount; + break; + + case value_t::BALANCE: + if (xact.cost) { + value.cast(value_t::BALANCE_PAIR); + return add_transaction_to(xact, value); + } + *((balance_t *) value.data) += xact.amount; + break; + + case value_t::BALANCE_PAIR: + add_transaction_to(xact, *((balance_pair_t *) value.data)); + break; + + default: + assert(0); + break; + } + + return value; +} + void entry_t::add_transaction(transaction_t * xact) { xact->entry = this; @@ -394,9 +448,6 @@ bool journal_t::valid() const using namespace boost::python; using namespace ledger; -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(journal_find_account_overloads, - find_account, 1, 2) - entry_t& transaction_entry(const transaction_t& xact) { return *xact.entry; @@ -504,8 +555,26 @@ account_t& accounts_getitem(account_t& account, int i) return *(*elem).second; } +account_t * py_find_account_1(journal_t& journal, const std::string& name) +{ + return journal.find_account(name); +} + +account_t * py_find_account_2(journal_t& journal, const std::string& name, + const bool auto_create) +{ + return journal.find_account(name, auto_create); +} + + void export_journal() { + scope().attr("TRANSACTION_NORMAL") = TRANSACTION_NORMAL; + scope().attr("TRANSACTION_VIRTUAL") = TRANSACTION_VIRTUAL; + scope().attr("TRANSACTION_BALANCE") = TRANSACTION_BALANCE; + scope().attr("TRANSACTION_AUTO") = TRANSACTION_AUTO; + scope().attr("TRANSACTION_BULK_ALLOC") = TRANSACTION_BULK_ALLOC; + class_< transaction_t > ("Transaction") .def(init<account_t *, amount_t, optional<unsigned int, std::string> >()) @@ -522,22 +591,6 @@ void export_journal() .def("valid", &transaction_t::valid) ; - 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("__len__", transactions_len) - .def("__getitem__", transactions_getitem, - return_value_policy<reference_existing_object>()) - - .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) @@ -565,16 +618,12 @@ void export_journal() .def_readonly("sources", &journal_t::sources) .def("__len__", entries_len) - .def("__getitem__", entries_getitem, - return_value_policy<reference_existing_object>()) + .def("__getitem__", entries_getitem, return_internal_reference<1>()) .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("find_account", py_find_account_1, return_internal_reference<1>()) + .def("find_account", py_find_account_2, return_internal_reference<1>()) .def("add_entry", &journal_t::add_entry) .def("remove_entry", &journal_t::remove_entry) @@ -583,6 +632,28 @@ void export_journal() .def("valid", &journal_t::valid) ; + + scope in_entry = 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("__len__", transactions_len) + .def("__getitem__", transactions_getitem, + return_internal_reference<1>()) + + .def("add_transaction", &entry_t::add_transaction) + .def("remove_transaction", &entry_t::remove_transaction) + + .def("valid", &entry_t::valid) + ; + + enum_< entry_t::state_t > ("State") + .value("UNCLEARED", entry_t::UNCLEARED) + .value("CLEARED", entry_t::CLEARED) + .value("PENDING", entry_t::PENDING) + ; } #endif // USE_BOOST_PYTHON @@ -65,75 +65,24 @@ class transaction_t bool valid() const; }; -inline balance_pair_t& add_transaction_to(const transaction_t& xact, - balance_pair_t& bal_pair) -{ - if (xact.cost && ! bal_pair.cost) - bal_pair.cost = new balance_t(bal_pair.quantity); - - bal_pair.quantity += xact.amount; - - if (bal_pair.cost) - *bal_pair.cost += xact.cost ? *xact.cost : xact.amount; - - return bal_pair; -} - -inline -value_t& add_transaction_to(const transaction_t& xact, value_t& value) -{ - switch (value.type) { - case value_t::BOOLEAN: - case value_t::INTEGER: - value.cast(value_t::AMOUNT); - - case value_t::AMOUNT: - if (xact.cost) { - value.cast(value_t::BALANCE_PAIR); - return add_transaction_to(xact, value); - } - else if (((amount_t *) value.data)->commodity() != - xact.amount.commodity()) { - value.cast(value_t::BALANCE); - return add_transaction_to(xact, value); - } - *((amount_t *) value.data) += xact.amount; - break; - - case value_t::BALANCE: - if (xact.cost) { - value.cast(value_t::BALANCE_PAIR); - return add_transaction_to(xact, value); - } - *((balance_t *) value.data) += xact.amount; - break; - - case value_t::BALANCE_PAIR: - add_transaction_to(xact, *((balance_pair_t *) value.data)); - break; - - default: - assert(0); - break; - } - - return value; -} + balance_pair_t& bal_pair); +value_t& add_transaction_to(const transaction_t& xact, value_t& value); typedef std::list<transaction_t *> transactions_list; class entry_t { public: - enum entry_state_t { + enum state_t { UNCLEARED, CLEARED, PENDING }; - std::time_t date; - entry_state_t state; - std::string code; - std::string payee; + std::time_t date; + state_t state; + std::string code; + std::string payee; + transactions_list transactions; entry_t() : date(-1), state(UNCLEARED) {} @@ -97,9 +97,9 @@ chain_formatters(const std::string& command, // sort_transactions will sort all the transactions it sees, based // on the `sort_order' value expression. - if (config.sort_order) + if (! config.sort_string.empty()) ptrs.push_back(formatter = - new sort_transactions(formatter, config.sort_order)); + new sort_transactions(formatter, config.sort_string)); // changed_value_transactions adds virtual transactions to the // list to account for changes in market value of commodities, @@ -128,7 +128,7 @@ chain_formatters(const std::string& command, // of the week. if (config.show_subtotal) ptrs.push_back(formatter = new subtotal_transactions(formatter)); - else if (config.report_interval) + else if (! config.report_interval.empty()) ptrs.push_back(formatter = new interval_transactions(formatter, config.report_interval)); @@ -271,13 +271,13 @@ int parse_and_report(int argc, char * argv[], char * envp[]) format_account acct_formatter(*out, config.format, config.display_predicate); sum_accounts(*journal->master); - walk_accounts(*journal->master, acct_formatter, config.sort_order); + walk_accounts(*journal->master, acct_formatter, config.sort_string); acct_formatter.flush(); - if (journal->master->data) { - ACCT_DATA(journal->master)->value = ACCT_DATA(journal->master)->total; - - if (ACCT_DATA(journal->master)->dflags & ACCOUNT_TO_DISPLAY) { + if (account_has_xdata(*journal->master)) { + account_xdata_t& xdata = account_xdata(*journal->master); + xdata.value = xdata.total; + if (xdata.dflags & ACCOUNT_TO_DISPLAY) { *out << "--------------------\n"; config.format.format(*out, details_t(*journal->master)); } @@ -287,7 +287,7 @@ int parse_and_report(int argc, char * argv[], char * envp[]) format_equity acct_formatter(*out, config.format, config.nformat, config.display_predicate); sum_accounts(*journal->master); - walk_accounts(*journal->master, acct_formatter, config.sort_order); + walk_accounts(*journal->master, acct_formatter, config.sort_string); acct_formatter.flush(); } @@ -300,14 +300,6 @@ int parse_and_report(int argc, char * argv[], char * envp[]) i != formatter_ptrs.end(); i++) delete *i; - - // Cleanup the data handlers that might be present on some objects. - - clear_transaction_data xact_cleanup; - walk_entries(journal->entries, xact_cleanup); - - clear_account_data acct_cleanup; - walk_accounts(*journal->master, acct_cleanup); #endif TIMER_STOP(report_gen); @@ -106,7 +106,7 @@ class FormatTransaction (TransactionHandler): self.output.flush () def __call__ (self, xact): - if self.nformatter and xact.entry is self.last_entry: + if self.nformatter is not None and xact.entry is self.last_entry: self.output.write(self.nformatter.format(xact)) else: self.output.write(self.formatter.format(xact)) @@ -123,8 +123,8 @@ if not (command == "b" or command == "E"): handler = CalcTransactions(handler, config.show_inverted) - if config.sort_order: - handler = SortTransactions(handler, config.sort_order) + if config.sort_string: + handler = SortTransactions(handler, config.sort_string) if config.show_revalued: handler = ChangedValueTransactions(handler, config.show_revalued_only) @@ -145,12 +145,14 @@ if config.show_related: if config.predicate: handler = FilterTransactions(handler, config.predicate) -if 1: +if 0: walk_entries (journal, handler) else: # These for loops are equivalent to `walk_entries', but far slower for entry in journal: + #print "1:", entry for xact in entry: + #print "2:", xact.entry handler (xact) handler.flush () @@ -159,7 +161,7 @@ handler.flush () # format_account acct_formatter(out, config.format, # config.display_predicate); # sum_accounts(*journal->master); -# walk_accounts(*journal->master, acct_formatter, config.sort_order); +# walk_accounts(*journal->master, acct_formatter, config.sort_string); # acct_formatter.flush(); # # if (journal->master->data) { @@ -174,7 +176,7 @@ handler.flush () # format_equity acct_formatter(out, config.format, config.nformat, # config.display_predicate); # sum_accounts(*journal->master); -# walk_accounts(*journal->master, acct_formatter, config.sort_order); +# walk_accounts(*journal->master, acct_formatter, config.sort_string); # acct_formatter.flush(); # } @@ -84,8 +84,8 @@ void value_expr_t::compute(value_t& result, const details_t& details) const case AMOUNT: if (details.xact) result = details.xact->amount; - else if (details.account && ACCT_DATA(details.account)) - result = ACCT_DATA(details.account)->value; + else if (details.account && account_has_xdata(*details.account)) + result = account_xdata(*details.account).value; break; case COST: @@ -95,22 +95,22 @@ void value_expr_t::compute(value_t& result, const details_t& details) const else result = details.xact->amount; } - else if (details.account && ACCT_DATA(details.account)) { - result = ACCT_DATA(details.account)->value.cost(); + else if (details.account && account_has_xdata(*details.account)) { + result = account_xdata(*details.account).value.cost(); } break; case TOTAL: - if (details.xact && XACT_DATA(details.xact)) - result = XACT_DATA(details.xact)->total; - else if (details.account && ACCT_DATA(details.account)) - result = ACCT_DATA(details.account)->total; + if (details.xact && transaction_has_xdata(*details.xact)) + result = transaction_xdata(*details.xact).total; + else if (details.account && account_has_xdata(*details.account)) + result = account_xdata(*details.account).total; break; case COST_TOTAL: - if (details.xact && XACT_DATA(details.xact)) - result = XACT_DATA(details.xact)->total.cost(); - else if (details.account && ACCT_DATA(details.account)) - result = ACCT_DATA(details.account)->total.cost(); + if (details.xact && transaction_has_xdata(*details.xact)) + result = transaction_xdata(*details.xact).total.cost(); + else if (details.account && account_has_xdata(*details.account)) + result = account_xdata(*details.account).total.cost(); break; case VALUE_EXPR: @@ -166,17 +166,17 @@ void value_expr_t::compute(value_t& result, const details_t& details) const break; case INDEX: - if (details.xact && XACT_DATA(details.xact)) - result = XACT_DATA(details.xact)->index + 1; - else if (details.account && ACCT_DATA(details.account)) - result = ACCT_DATA(details.account)->subcount; + if (details.xact && transaction_has_xdata(*details.xact)) + result = transaction_xdata(*details.xact).index + 1; + else if (details.account && account_has_xdata(*details.account)) + result = account_xdata(*details.account).subcount; break; case COUNT: - if (details.xact && XACT_DATA(details.xact)) - result = XACT_DATA(details.xact)->index + 1; - else if (details.account && ACCT_DATA(details.account)) - result = ACCT_DATA(details.account)->count; + if (details.xact && transaction_has_xdata(*details.xact)) + result = transaction_xdata(*details.xact).index + 1; + else if (details.account && account_has_xdata(*details.account)) + result = account_xdata(*details.account).count; break; case DEPTH: @@ -187,17 +187,16 @@ void value_expr_t::compute(value_t& result, const details_t& details) const break; case F_ARITH_MEAN: - if (details.xact && XACT_DATA(details.xact)) { + if (details.xact && transaction_has_xdata(*details.xact)) { assert(left); left->compute(result, details); - result /= amount_t(XACT_DATA(details.xact)->index + 1); + result /= amount_t(transaction_xdata(*details.xact).index + 1); } - else if (details.account && - ACCT_DATA(details.account) && - ACCT_DATA(details.account)->count) { + else if (details.account && account_has_xdata(*details.account) && + account_xdata(*details.account).count) { assert(left); left->compute(result, details); - result /= amount_t(ACCT_DATA(details.account)->count); + result /= amount_t(account_xdata(*details.account).count); } break; @@ -3,6 +3,9 @@ namespace ledger { +std::list<transaction_xdata_t> transactions_xdata; +std::list<account_xdata_t> accounts_xdata; + void sort_transactions::flush() { std::stable_sort(transactions.begin(), transactions.end(), @@ -20,14 +23,11 @@ void sort_transactions::flush() void calc_transactions::operator()(transaction_t& xact) { - if (! xact.data) - xact.data = new transaction_data_t; - - if (last_xact && last_xact->data) { - XACT_DATA_(xact)->total += XACT_DATA(last_xact)->total; - XACT_DATA_(xact)->index = XACT_DATA(last_xact)->index + 1; + if (last_xact && transaction_has_xdata(*last_xact)) { + transaction_xdata(xact).total += transaction_xdata(*last_xact).total; + transaction_xdata(xact).index = transaction_xdata(*last_xact).index + 1; } else { - XACT_DATA_(xact)->index = 0; + transaction_xdata(xact).index = 0; } if (inverted) { @@ -36,8 +36,8 @@ void calc_transactions::operator()(transaction_t& xact) xact.cost->negate(); } - if (! (XACT_DATA_(xact)->dflags & TRANSACTION_NO_TOTAL)) - add_transaction_to(xact, XACT_DATA_(xact)->total); + if (! (transaction_xdata(xact).dflags & TRANSACTION_NO_TOTAL)) + add_transaction_to(xact, transaction_xdata(xact).total); (*handler)(xact); @@ -51,9 +51,11 @@ void calc_transactions::operator()(transaction_t& xact) } -static void handle_value(const value_t& value, account_t * account, - entry_t * entry, unsigned int flags, - transactions_list& temps, +static 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) { balance_t * bal = NULL; @@ -62,32 +64,29 @@ static void handle_value(const value_t& value, account_t * account, case value_t::BOOLEAN: case value_t::INTEGER: case value_t::AMOUNT: { - transaction_t * xact = new transaction_t(account); - temps.push_back(xact); + temps.push_back(transaction_t(account)); + transaction_t& xact = temps.back(); - xact->entry = entry; + xact.entry = entry; switch (value.type) { case value_t::BOOLEAN: - xact->amount = *((bool *) value.data); + xact.amount = *((bool *) value.data); break; case value_t::INTEGER: - xact->amount = *((unsigned int *) value.data); + xact.amount = *((unsigned int *) value.data); break; case value_t::AMOUNT: - xact->amount = *((amount_t *) value.data); + xact.amount = *((amount_t *) value.data); break; default: assert(0); break; } - if (flags) { - if (! xact->data) - xact->data = new transaction_data_t; - XACT_DATA(xact)->dflags |= flags; - } + if (flags) + transaction_xdata(xact).dflags |= flags; - (*handler)(*xact); + (*handler)(xact); break; } @@ -102,19 +101,16 @@ static void handle_value(const value_t& value, account_t * account, for (amounts_map::const_iterator i = bal->amounts.begin(); i != bal->amounts.end(); i++) { - transaction_t * xact = new transaction_t(account); - temps.push_back(xact); + temps.push_back(transaction_t(account)); + transaction_t& xact = temps.back(); - xact->entry = entry; - xact->amount = (*i).second; + xact.entry = entry; + xact.amount = (*i).second; - if (flags) { - if (! xact->data) - xact->data = new transaction_data_t; - XACT_DATA(xact)->dflags |= flags; - } + if (flags) + transaction_xdata(xact).dflags |= flags; - (*handler)(*xact); + (*handler)(xact); } break; @@ -131,12 +127,12 @@ void collapse_transactions::report_cumulative_subtotal() } else { assert(count > 1); - if (! totals_account->data) - totals_account->data = new account_data_t; - ACCT_DATA(totals_account)->total = subtotal; + account_xdata_t xdata; + xdata.total = subtotal; value_t result; - format_t::compute_total(result, details_t(*totals_account)); - handle_value(result, totals_account, last_entry, 0, xact_temps, handler); + totals_account.data = &xdata; + format_t::compute_total(result, details_t(totals_account)); + handle_value(result, &totals_account, last_entry, 0, xact_temps, handler); } subtotal = 0; @@ -157,13 +153,13 @@ void changed_value_transactions::output_diff(const std::time_t current) cur_bal -= prev_bal; if (cur_bal) { - entry_t * entry = new entry_t; - entry_temps.push_back(entry); + entry_temps.push_back(entry_t()); + entry_t& entry = entry_temps.back(); - entry->payee = "Commodities revalued"; - entry->date = current; + entry.payee = "Commodities revalued"; + entry.date = current; - handle_value(cur_bal, NULL, entry, TRANSACTION_NO_TOTAL, xact_temps, + handle_value(cur_bal, NULL, &entry, TRANSACTION_NO_TOTAL, xact_temps, handler); } } @@ -173,11 +169,8 @@ void changed_value_transactions::operator()(transaction_t& xact) if (last_xact) output_diff(xact.entry->date); - if (changed_values_only) { - if (! xact.data) - xact.data = new transaction_data_t; - XACT_DATA_(xact)->dflags |= TRANSACTION_DISPLAYED; - } + if (changed_values_only) + transaction_xdata(xact).dflags |= TRANSACTION_DISPLAYED; (*handler)(xact); @@ -201,31 +194,28 @@ void subtotal_transactions::flush(const char * spec_fmt) std::strftime(buf, 255, spec_fmt, std::localtime(&finish)); } - entry_t * entry = new entry_t; - entry_temps.push_back(entry); + entry_temps.push_back(entry_t()); + entry_t& entry = entry_temps.back(); - entry->payee = buf; + entry.payee = buf; value_t result; for (balances_map::iterator i = balances.begin(); i != balances.end(); i++) { - entry->date = finish; + entry.date = finish; { + transaction_xdata_t xact_data; + xact_data.total = (*i).second; transaction_t temp((*i).first); - temp.entry = entry; - { - std::auto_ptr<transaction_data_t> xact_data(new transaction_data_t); - temp.data = xact_data.get(); - ((transaction_data_t *) temp.data)->total = (*i).second; - format_t::compute_total(result, details_t(temp)); - } - temp.data = NULL; + temp.entry = &entry; + temp.data = &xact_data; + format_t::compute_total(result, details_t(temp)); } - entry->date = start; + entry.date = start; - handle_value(result, (*i).first, entry, 0, xact_temps, handler); + handle_value(result, (*i).first, &entry, 0, xact_temps, handler); } balances.clear(); @@ -256,6 +246,12 @@ void subtotal_transactions::operator()(transaction_t& xact) void interval_transactions::operator()(transaction_t& xact) { + if ((interval.begin && + std::difftime(xact.entry->date, interval.begin) < 0) || + (interval.end && + std::difftime(xact.entry->date, interval.end) >= 0)) + return; + std::time_t quant = interval.increment(interval.begin); if (std::difftime(xact.entry->date, quant) > 0) { if (last_xact) { @@ -349,6 +345,19 @@ void export_walk() { typedef item_handler<transaction_t> xact_handler_t; + scope().attr("TRANSACTION_HANDLED") = TRANSACTION_HANDLED; + scope().attr("TRANSACTION_DISPLAYED") = TRANSACTION_DISPLAYED; + scope().attr("TRANSACTION_NO_TOTAL") = TRANSACTION_NO_TOTAL; + + class_< transaction_xdata_t > ("TransactionXData") + .def_readwrite("total", &transaction_xdata_t::total) + .def_readwrite("index", &transaction_xdata_t::index) + .def_readwrite("dflags", &transaction_xdata_t::dflags) + ; + + def("transaction_has_xdata", transaction_has_xdata); + def("transaction_xdata", transaction_xdata, return_internal_reference<1>()); + class_< xact_handler_t, item_handler_wrap<transaction_t> > ("TransactionHandler") .def(init<xact_handler_t *>()) @@ -365,12 +374,6 @@ void export_walk() .def("__call__", &ignore_transactions::operator()); ; - class_< clear_transaction_data, bases<xact_handler_t> > - ("ClearTransactionData") - .def("flush", &xact_handler_t::flush) - .def("__call__", &clear_transaction_data::operator()); - ; - class_< set_account_value, bases<xact_handler_t> > ("SetAccountValue", init<xact_handler_t *>() [with_custodian_and_ward<1, 2>()]) @@ -381,6 +384,8 @@ void export_walk() class_< sort_transactions, bases<xact_handler_t> > ("SortTransactions", init<xact_handler_t *, const value_expr_t *>() [with_custodian_and_ward<1, 2>()]) + .def(init<xact_handler_t *, const std::string&>() + [with_custodian_and_ward<1, 2>()]) .def("flush", &sort_transactions::flush) .def("__call__", &sort_transactions::operator()); ; @@ -388,6 +393,8 @@ void export_walk() class_< filter_transactions, bases<xact_handler_t> > ("FilterTransactions", init<xact_handler_t *, std::string>() [with_custodian_and_ward<1, 2>()]) + .def(init<xact_handler_t *, const std::string&>() + [with_custodian_and_ward<1, 2>()]) .def("flush", &xact_handler_t::flush) .def("__call__", &filter_transactions::operator()); ; @@ -423,6 +430,8 @@ void export_walk() class_< interval_transactions, bases<xact_handler_t> > ("IntervalTransactions", init<xact_handler_t *, interval_t>() [with_custodian_and_ward<1, 2>()]) + .def(init<xact_handler_t *, const std::string&>() + [with_custodian_and_ward<1, 2>()]) .def("flush", &xact_handler_t::flush) .def("__call__", &interval_transactions::operator()); ; @@ -65,6 +65,42 @@ class compare_items { // Transaction handlers // +#define TRANSACTION_HANDLED 0x0001 +#define TRANSACTION_DISPLAYED 0x0002 +#define TRANSACTION_NO_TOTAL 0x0004 + +struct transaction_xdata_t +{ + value_t total; + unsigned int index; + unsigned short dflags; + + transaction_xdata_t() : index(0), dflags(0) { + DEBUG_PRINT("ledger.memory.ctors", "ctor transaction_xdata_t"); + } +#ifdef DEBUG_ENABLED + ~transaction_xdata_t() { + DEBUG_PRINT("ledger.memory.dtors", "dtor transaction_xdata_t"); + } +#endif +}; + +inline bool transaction_has_xdata(const transaction_t& xact) { + return xact.data != NULL; +} + +extern std::list<transaction_xdata_t> transactions_xdata; + +inline transaction_xdata_t& transaction_xdata(const transaction_t& xact) { + if (! xact.data) { + transactions_xdata.push_back(transaction_xdata_t()); + xact.data = &transactions_xdata.back(); + } + return *((transaction_xdata_t *) xact.data); +} + +////////////////////////////////////////////////////////////////////// + typedef std::deque<transaction_t *> transactions_deque; typedef std::deque<entry_t *> entries_deque; @@ -73,6 +109,7 @@ inline void walk_transactions(transactions_list::iterator begin, item_handler<transaction_t>& handler) { for (transactions_list::iterator i = begin; i != end; i++) handler(**i); + transactions_xdata.clear(); } inline void walk_transactions(transactions_list& list, @@ -85,6 +122,7 @@ inline void walk_transactions(transactions_deque::iterator begin, item_handler<transaction_t>& handler) { for (transactions_deque::iterator i = begin; i != end; i++) handler(**i); + transactions_xdata.clear(); } inline void walk_transactions(transactions_deque& deque, @@ -106,100 +144,43 @@ inline void walk_entries(entries_list& list, ////////////////////////////////////////////////////////////////////// -#define TRANSACTION_HANDLED 0x0001 -#define TRANSACTION_DISPLAYED 0x0002 -#define TRANSACTION_NO_TOTAL 0x0004 - -struct transaction_data_t -{ - value_t total; - unsigned int index; - unsigned short dflags; - - transaction_data_t() : index(0), dflags(0) { - DEBUG_PRINT("ledger.memory.ctors", "ctor transaction_data_t"); - } -#ifdef DEBUG_ENABLED - ~transaction_data_t() { - DEBUG_PRINT("ledger.memory.dtors", "dtor transaction_data_t"); - } -#endif -}; - -#define XACT_DATA(xact) ((transaction_data_t *) ((xact)->data)) -#define XACT_DATA_(xact) ((transaction_data_t *) ((xact).data)) - -#define ACCOUNT_DISPLAYED 0x1 -#define ACCOUNT_TO_DISPLAY 0x2 - -struct account_data_t -{ - value_t value; - value_t total; - unsigned int count; // transactions counted toward total - unsigned int subcount; - unsigned short dflags; - - account_data_t() : count(0), subcount(0), dflags(0) { - DEBUG_PRINT("ledger.memory.ctors", "ctor account_data_t"); - } -#ifdef DEBUG_ENABLED - ~account_data_t() { - DEBUG_PRINT("ledger.memory.dtors", "dtor account_data_t"); - } -#endif -}; - -#define ACCT_DATA(acct) ((account_data_t *) ((acct)->data)) -#define ACCT_DATA_(acct) ((account_data_t *) ((acct).data)) - -////////////////////////////////////////////////////////////////////// - class ignore_transactions : public item_handler<transaction_t> { public: virtual void operator()(transaction_t& xact) {} }; -class clear_transaction_data : public item_handler<transaction_t> -{ - public: - virtual void operator()(transaction_t& xact) { - if (xact.data) { - delete (transaction_data_t *) xact.data; - xact.data = NULL; - } - } -}; - class set_account_value : public item_handler<transaction_t> { public: set_account_value(item_handler<transaction_t> * handler = NULL) : item_handler<transaction_t>(handler) {} - virtual void operator()(transaction_t& xact) { - if (! ACCT_DATA(xact.account)) - xact.account->data = new account_data_t; - - add_transaction_to(xact, ACCT_DATA(xact.account)->value); - ACCT_DATA(xact.account)->subcount++; - - if (handler) - (*handler)(xact); - } + virtual void operator()(transaction_t& xact); }; class sort_transactions : public item_handler<transaction_t> { transactions_deque transactions; const value_expr_t * sort_order; + bool allocated; public: sort_transactions(item_handler<transaction_t> * handler, const value_expr_t * _sort_order) : item_handler<transaction_t>(handler), - sort_order(_sort_order) {} + sort_order(_sort_order), allocated(false) {} + + sort_transactions(item_handler<transaction_t> * handler, + const std::string& _sort_order) + : item_handler<transaction_t>(handler), + sort_order(parse_value_expr(_sort_order)), allocated(true) {} + + virtual ~sort_transactions() { + assert(sort_order); + if (allocated) + delete sort_order; + } virtual void flush(); virtual void operator()(transaction_t& xact) { @@ -209,15 +190,28 @@ class sort_transactions : public item_handler<transaction_t> class filter_transactions : public item_handler<transaction_t> { - item_predicate<transaction_t> pred; + const item_predicate<transaction_t> * pred; + bool allocated; public: filter_transactions(item_handler<transaction_t> * handler, + const item_predicate<transaction_t> * predicate) + : item_handler<transaction_t>(handler), + pred(predicate), allocated(false) {} + + filter_transactions(item_handler<transaction_t> * handler, const std::string& predicate) - : item_handler<transaction_t>(handler), pred(predicate) {} + : item_handler<transaction_t>(handler), + pred(new item_predicate<transaction_t>(predicate)), + allocated(true) {} + + virtual ~filter_transactions() { + if (allocated) + delete pred; + } virtual void operator()(transaction_t& xact) { - if (pred(xact)) + if ((*pred)(xact)) (*handler)(xact); } }; @@ -238,36 +232,18 @@ class calc_transactions : public item_handler<transaction_t> class collapse_transactions : public item_handler<transaction_t> { - balance_pair_t subtotal; - unsigned int count; - entry_t * last_entry; - transaction_t * last_xact; - account_t * totals_account; - transactions_list xact_temps; + balance_pair_t subtotal; + unsigned int count; + entry_t * last_entry; + transaction_t * last_xact; + account_t totals_account; + + std::list<transaction_t> xact_temps; public: collapse_transactions(item_handler<transaction_t> * handler) : item_handler<transaction_t>(handler), count(0), - last_entry(NULL), last_xact(NULL) { - totals_account = new account_t(NULL, "<Total>"); - } - - virtual ~collapse_transactions() { - if (totals_account->data) { - delete (account_data_t *) totals_account->data; - totals_account->data = NULL; - } - delete totals_account; - for (transactions_list::iterator i = xact_temps.begin(); - i != xact_temps.end(); - i++) { - if ((*i)->data) { - delete (transaction_data_t *) (*i)->data; - (*i)->data = NULL; - } - delete *i; - } - } + last_entry(NULL), last_xact(NULL), totals_account(NULL, "<Total>") {} virtual void flush() { if (subtotal) @@ -297,10 +273,10 @@ class changed_value_transactions : public item_handler<transaction_t> // This filter requires that calc_transactions be used at some point // later in the chain. - bool changed_values_only; - transaction_t * last_xact; - entries_list entry_temps; - transactions_list xact_temps; + bool changed_values_only; + transaction_t * last_xact; + std::list<entry_t> entry_temps; + std::list<transaction_t> xact_temps; public: changed_value_transactions(item_handler<transaction_t> * handler, @@ -308,23 +284,6 @@ class changed_value_transactions : public item_handler<transaction_t> : item_handler<transaction_t>(handler), changed_values_only(_changed_values_only), last_xact(NULL) {} - virtual ~changed_value_transactions() { - for (entries_list::iterator i = entry_temps.begin(); - i != entry_temps.end(); - i++) - delete *i; - - for (transactions_list::iterator i = xact_temps.begin(); - i != xact_temps.end(); - i++) { - if ((*i)->data) { - delete (transaction_data_t *) (*i)->data; - (*i)->data = NULL; - } - delete *i; - } - } - virtual void flush() { output_diff(std::time(NULL)); last_xact = NULL; @@ -342,33 +301,16 @@ class subtotal_transactions : public item_handler<transaction_t> typedef std::pair<account_t *, balance_pair_t> balances_pair; protected: - std::time_t start; - std::time_t finish; - balances_map balances; - entries_list entry_temps; - transactions_list xact_temps; + std::time_t start; + std::time_t finish; + balances_map balances; + std::list<entry_t> entry_temps; + std::list<transaction_t> xact_temps; public: subtotal_transactions(item_handler<transaction_t> * handler) : item_handler<transaction_t>(handler) {} - virtual ~subtotal_transactions() { - for (entries_list::iterator i = entry_temps.begin(); - i != entry_temps.end(); - i++) - delete *i; - - for (transactions_list::iterator i = xact_temps.begin(); - i != xact_temps.end(); - i++) { - if ((*i)->data) { - delete (transaction_data_t *) (*i)->data; - (*i)->data = NULL; - } - delete *i; - } - } - void flush(const char * spec_fmt); virtual void flush() { @@ -388,6 +330,11 @@ class interval_transactions : public subtotal_transactions : subtotal_transactions(handler), interval(_interval), last_xact(NULL) {} + interval_transactions(item_handler<transaction_t> * handler, + const std::string& _interval) + : subtotal_transactions(handler), interval(_interval), + last_xact(NULL) {} + virtual ~interval_transactions() { start = interval.begin; finish = interval.increment(interval.begin); @@ -425,13 +372,11 @@ class related_transactions : public item_handler<transaction_t> for (transactions_list::iterator i = xact.entry->transactions.begin(); i != xact.entry->transactions.end(); i++) - if ((! (*i)->data || - ! (XACT_DATA(*i)->dflags & TRANSACTION_HANDLED)) && + if ((! transaction_has_xdata(**i) || + ! (transaction_xdata(**i).dflags & TRANSACTION_HANDLED)) && (*i == &xact ? also_matching : ! ((*i)->flags & TRANSACTION_AUTO))) { - if (! (*i)->data) - (*i)->data = new transaction_data_t; - XACT_DATA(*i)->dflags |= TRANSACTION_HANDLED; + transaction_xdata(**i).dflags |= TRANSACTION_HANDLED; (*handler)(**i); } } @@ -443,31 +388,62 @@ class related_transactions : public item_handler<transaction_t> // Account walking functions // -class clear_account_data : public item_handler<account_t> +#define ACCOUNT_DISPLAYED 0x1 +#define ACCOUNT_TO_DISPLAY 0x2 + +struct account_xdata_t { - public: - virtual void operator()(account_t * account) { - if (account->data) { - delete (account_data_t *) account->data; - account->data = NULL; - } + value_t value; + value_t total; + unsigned int count; // transactions counted toward total + unsigned int subcount; + unsigned short dflags; + + account_xdata_t() : count(0), subcount(0), dflags(0) { + DEBUG_PRINT("ledger.memory.ctors", "ctor account_xdata_t"); + } +#ifdef DEBUG_ENABLED + ~account_xdata_t() { + DEBUG_PRINT("ledger.memory.dtors", "dtor account_xdata_t"); } +#endif }; -inline void sum_accounts(account_t& account) { - if (! account.data) - account.data = new account_data_t; +inline bool account_has_xdata(const account_t& account) { + return account.data != NULL; +} + +extern std::list<account_xdata_t> accounts_xdata; + +inline account_xdata_t& account_xdata(const account_t& account) { + if (! account.data) { + accounts_xdata.push_back(account_xdata_t()); + account.data = &accounts_xdata.back(); + } + return *((account_xdata_t *) account.data); +} + +inline void set_account_value::operator()(transaction_t& xact) { + add_transaction_to(xact, account_xdata(*xact.account).value); + account_xdata(*xact.account).subcount++; + + if (handler) + (*handler)(xact); +} + +////////////////////////////////////////////////////////////////////// +inline void sum_accounts(account_t& account) { for (accounts_map::iterator i = account.accounts.begin(); i != account.accounts.end(); i++) { sum_accounts(*(*i).second); - ACCT_DATA_(account)->total += ACCT_DATA((*i).second)->total; - ACCT_DATA_(account)->count += (ACCT_DATA((*i).second)->count + - ACCT_DATA((*i).second)->subcount); + account_xdata(account).total += account_xdata(*(*i).second).total; + account_xdata(account).count += (account_xdata(*(*i).second).count + + account_xdata(*(*i).second).subcount); } - ACCT_DATA_(account)->total += ACCT_DATA_(account)->value; - ACCT_DATA_(account)->count += ACCT_DATA_(account)->subcount; + account_xdata(account).total += account_xdata(account).value; + account_xdata(account).count += account_xdata(account).subcount; } typedef std::deque<account_t *> accounts_deque; @@ -502,6 +478,14 @@ inline void walk_accounts(account_t& account, i++) walk_accounts(*(*i).second, handler); } + accounts_xdata.clear(); +} + +inline void walk_accounts(account_t& account, + item_handler<account_t>& handler, + const std::string& sort_string) { + std::auto_ptr<value_expr_t> sort_order(parse_value_expr(sort_string)); + walk_accounts(account, handler, sort_order.get()); } } // namespace ledger |