ledger/walk.cc
John Wiegley 99313ebc6c Revised the way that exceptions are thrown around. Instead of context being a
complicated string of pointers, it's now just a global block of text that gets
appended to as the error is being thrown up, and can be displayed at the catch
point if desired.  There are almost no cases where a thrown exception will not
result in an error message being displayed to the user.
2008-07-31 06:24:45 -04:00

1025 lines
24 KiB
C++

#include "walk.h"
#include "session.h"
#include "format.h"
#include "textual.h"
#include <algorithm>
namespace ledger {
template <>
bool compare_items<xact_t>::operator()(const xact_t * left,
const xact_t * right)
{
assert(left);
assert(right);
#if 0
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 |= XACT_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 |= XACT_SORT_CALC;
}
DEBUG("ledger.walk.compare_items_xact",
"lxdata.sort_value = " << lxdata.sort_value);
DEBUG("ledger.walk.compare_items_xact",
"rxdata.sort_value = " << rxdata.sort_value);
return lxdata.sort_value < rxdata.sort_value;
#else
return false;
#endif
}
xact_xdata_t& xact_xdata(const xact_t& xact)
{
if (! xact.data)
xact.data = new xact_xdata_t();
return *static_cast<xact_xdata_t *>(xact.data);
}
void add_xact_to(const xact_t& xact, value_t& 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())) {
value.add(xact.amount, xact.cost);
}
else {
value = xact.amount;
}
}
void entries_iterator::reset(session_t& session)
{
journals_i = session.journals.begin();
journals_end = session.journals.end();
journals_uninitialized = false;
if (journals_i != journals_end) {
entries_i = (*journals_i).entries.begin();
entries_end = (*journals_i).entries.end();
entries_uninitialized = false;
} else {
entries_uninitialized = true;
}
}
entry_t * entries_iterator::operator()()
{
if (entries_i == entries_end) {
journals_i++;
if (journals_i == journals_end)
return NULL;
entries_i = (*journals_i).entries.begin();
entries_end = (*journals_i).entries.end();
}
return *entries_i++;
}
void session_xacts_iterator::reset(session_t& session)
{
entries.reset(session);
entry_t * entry = entries();
if (entry != NULL)
xacts.reset(*entry);
}
xact_t * session_xacts_iterator::operator()()
{
xact_t * xact = xacts();
if (xact == NULL) {
entry_t * entry = entries();
if (entry != NULL) {
xacts.reset(*entry);
xact = xacts();
}
}
return xact;
}
void truncate_entries::flush()
{
if (! xacts.size())
return;
entry_t * last_entry = (*xacts.begin())->entry;
int l = 0;
for (xacts_list::iterator x = xacts.begin();
x != xacts.end();
x++)
if (last_entry != (*x)->entry) {
l++;
last_entry = (*x)->entry;
}
l++;
last_entry = (*xacts.begin())->entry;
int i = 0;
for (xacts_list::iterator x = xacts.begin();
x != xacts.end();
x++) {
if (last_entry != (*x)->entry) {
last_entry = (*x)->entry;
i++;
}
bool print = false;
if (head_count) {
if (head_count > 0 && i < head_count)
print = true;
else if (head_count < 0 && i >= - head_count)
print = true;
}
if (! print && tail_count) {
if (tail_count > 0 && l - i <= tail_count)
print = true;
else if (tail_count < 0 && l - i > - tail_count)
print = true;
}
if (print)
item_handler<xact_t>::operator()(**x);
}
xacts.clear();
item_handler<xact_t>::flush();
}
void set_account_value::operator()(xact_t& xact)
{
account_t * acct = xact_account(xact);
assert(acct);
account_xdata_t& xdata = account_xdata(*acct);
add_xact_to(xact, xdata.value);
xdata.count++;
if (xact.has_flags(XACT_VIRTUAL))
xdata.virtuals++;
item_handler<xact_t>::operator()(xact);
}
void sort_xacts::post_accumulated_xacts()
{
std::stable_sort(xacts.begin(), xacts.end(),
compare_items<xact_t>(sort_order));
for (xacts_deque::iterator i = xacts.begin();
i != xacts.end();
i++) {
xact_xdata(**i).dflags &= ~XACT_SORT_CALC;
item_handler<xact_t>::operator()(**i);
}
xacts.clear();
}
void calc_xacts::operator()(xact_t& xact)
{
try {
xact_xdata_t& xdata(xact_xdata(xact));
if (last_xact && xact_has_xdata(*last_xact)) {
if (xdata.total.is_null())
xdata.total = xact_xdata_(*last_xact).total;
else
xdata.total += xact_xdata_(*last_xact).total;
xdata.index = xact_xdata_(*last_xact).index + 1;
} else {
xdata.index = 0;
}
if (! (xdata.dflags & XACT_NO_TOTAL))
add_xact_to(xact, xdata.total);
item_handler<xact_t>::operator()(xact);
last_xact = &xact;
}
catch (const std::exception& err) {
add_error_context("Calculating transaction at");
#if 0
add_error_context(xact_context(xact));
#endif
throw err;
}
}
void invert_xacts::operator()(xact_t& xact)
{
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<xact_t>::operator()(xact);
}
static inline
void handle_value(const value_t& value,
account_t * account,
entry_t * entry,
unsigned int flags,
std::list<xact_t>& temps,
item_handler<xact_t>& handler,
const datetime_t& date = datetime_t(),
xacts_list * component_xacts = NULL)
{
temps.push_back(xact_t(account));
xact_t& xact(temps.back());
xact.entry = entry;
xact.add_flags(XACT_TEMP);
entry->add_xact(&xact);
// If there are component xacts to associate with this
// temporary, do so now.
if (component_xacts)
xact_xdata(xact).copy_component_xacts(*component_xacts);
// 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(XACT_VIRTUAL);
if (! (account_xdata_(*account).dflags & ACCOUNT_HAS_UNB_VIRTUALS))
xact.add_flags(XACT_BALANCE);
}
xact_xdata_t& xdata(xact_xdata(xact));
if (is_valid(date))
xdata.date = date;
value_t temp(value);
switch (value.type()) {
case value_t::BOOLEAN:
case value_t::DATETIME:
case value_t::INTEGER:
temp.cast(value_t::AMOUNT);
// fall through...
case value_t::AMOUNT:
xact.amount = temp.as_amount();
break;
case value_t::BALANCE:
case value_t::BALANCE_PAIR:
xdata.value = temp;
flags |= XACT_COMPOUND;
break;
default:
assert(false); // jww (2008-04-24): What to do here?
break;
}
if (flags)
xdata.dflags |= flags;
handler(xact);
}
void collapse_xacts::report_subtotal()
{
assert(count >= 1);
if (count == 1) {
item_handler<xact_t>::operator()(*last_xact);
} else {
entry_temps.push_back(entry_t());
entry_t& entry = entry_temps.back();
entry.payee = last_entry->payee;
entry._date = last_entry->_date;
handle_value(subtotal, &totals_account, last_entry, 0, xact_temps,
*handler);
}
last_entry = NULL;
last_xact = NULL;
subtotal = 0L;
count = 0;
}
void collapse_xacts::operator()(xact_t& xact)
{
// If we've reached a new entry, report on the subtotal
// accumulated thus far.
if (last_entry && last_entry != xact.entry && count > 0)
report_subtotal();
add_xact_to(xact, subtotal);
count++;
last_entry = xact.entry;
last_xact = &xact;
}
void related_xacts::flush()
{
if (xacts.size() > 0) {
for (xacts_list::iterator i = xacts.begin();
i != xacts.end();
i++) {
if ((*i)->entry) {
for (xacts_list::iterator j = (*i)->entry->xacts.begin();
j != (*i)->entry->xacts.end();
j++) {
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 |= 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.
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<xact_t>::flush();
}
void changed_value_xacts::output_diff(const datetime_t& current)
{
value_t cur_bal;
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
xact_xdata(*last_xact).date = 0;
#endif
if (value_t diff = cur_bal - last_balance) {
entry_temps.push_back(entry_t());
entry_t& entry = entry_temps.back();
entry.payee = "Commodities revalued";
entry._date = current;
handle_value(diff, NULL, &entry, XACT_NO_TOTAL, xact_temps,
*handler);
}
}
void changed_value_xacts::operator()(xact_t& xact)
{
if (last_xact) {
datetime_t moment;
if (xact_has_xdata(*last_xact))
moment = xact_xdata_(*last_xact).date;
else
moment = xact.date();
output_diff(moment);
}
if (changed_values_only)
xact_xdata(xact).dflags |= XACT_DISPLAYED;
item_handler<xact_t>::operator()(xact);
#if 0
compute_total(last_balance, details_t(xact));
#endif
last_balance.round();
last_xact = &xact;
}
void component_xacts::operator()(xact_t& xact)
{
if (handler && pred(xact)) {
if (xact_has_xdata(xact) &&
xact_xdata_(xact).have_component_xacts())
xact_xdata_(xact).walk_component_xacts(*handler);
else
(*handler)(xact);
}
}
void subtotal_xacts::report_subtotal(const char * spec_fmt)
{
std::ostringstream out_date;
if (! spec_fmt) {
string fmt = "- ";
fmt += output_time_format; // jww (2008-04-24): output_date_format?
// jww (2008-04-24): There is no date output function?
#if 0
finish.write(out_date, fmt);
#endif
} else {
#if 0
finish.write(out_date, spec_fmt);
#endif
}
entry_temps.push_back(entry_t());
entry_t& entry = entry_temps.back();
entry.payee = out_date.str();
entry._date = start;
for (values_map::iterator i = values.begin();
i != values.end();
i++)
handle_value((*i).second.value, (*i).second.account, &entry, 0,
xact_temps, *handler, finish, &(*i).second.components);
values.clear();
}
void subtotal_xacts::operator()(xact_t& xact)
{
if (! is_valid(start) || xact.date() < start)
start = xact.date();
if (! is_valid(finish) || xact.date() > finish)
finish = xact.date();
account_t * acct = xact_account(xact);
assert(acct);
values_map::iterator i = values.find(acct->fullname());
if (i == values.end()) {
value_t 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);
if (remember_components)
(*result.first).second.components.push_back(&xact);
} else {
add_xact_to(xact, (*i).second.value);
if (remember_components)
(*i).second.components.push_back(&xact);
}
// 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 xacts.
if (! xact.has_flags(XACT_VIRTUAL))
account_xdata(*xact_account(xact)).dflags |= ACCOUNT_HAS_NON_VIRTUALS;
else if (! xact.has_flags(XACT_BALANCE))
account_xdata(*xact_account(xact)).dflags |= ACCOUNT_HAS_UNB_VIRTUALS;
}
void interval_xacts::report_subtotal(const datetime_t& moment)
{
assert(last_xact);
start = interval.begin;
if (is_valid(moment))
// jww (2008-04-24): How to change this back into a datetime?
#if 0
finish = moment - 86400L;
#else
;
#endif
else
finish = last_xact->date();
subtotal_xacts::report_subtotal();
last_xact = NULL;
}
void interval_xacts::operator()(xact_t& xact)
{
const datetime_t date = xact.date();
if ((is_valid(interval.begin) && date < interval.begin) ||
(is_valid(interval.end) && date >= interval.end))
return;
if (interval) {
if (! started) {
if (! is_valid(interval.begin))
interval.start(date);
start = interval.begin;
started = true;
}
datetime_t quant = interval.increment(interval.begin);
if (date >= quant) {
if (last_xact)
report_subtotal(quant);
datetime_t temp;
while (date >= (temp = interval.increment(quant))) {
if (quant == temp)
break;
quant = temp;
}
start = interval.begin = quant;
}
subtotal_xacts::operator()(xact);
} else {
item_handler<xact_t>::operator()(xact);
}
last_xact = &xact;
}
by_payee_xacts::~by_payee_xacts()
{
TRACE_DTOR(by_payee_xacts);
for (payee_subtotals_map::iterator i = payee_subtotals.begin();
i != payee_subtotals.end();
i++)
checked_delete((*i).second);
}
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<xact_t>::flush();
payee_subtotals.clear();
}
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_xacts(handler, remember_components));
std::pair<payee_subtotals_map::iterator, bool> result
= payee_subtotals.insert(temp);
assert(result.second);
if (! result.second)
return;
i = result.first;
}
if (xact.date() > (*i).second->start)
(*i).second->start = xact.date();
(*(*i).second)(xact);
}
void set_comm_as_payee::operator()(xact_t& xact)
{
entry_temps.push_back(*xact.entry);
entry_t& entry = entry_temps.back();
entry._date = xact.date();
entry.code = xact.entry->code;
if (xact.amount.commodity())
entry.payee = xact.amount.commodity().symbol();
else
entry.payee = "<none>";
xact_temps.push_back(xact);
xact_t& temp = xact_temps.back();
temp.entry = &entry;
temp.state = xact.state;
temp.add_flags(XACT_TEMP);
entry.add_xact(&temp);
item_handler<xact_t>::operator()(temp);
}
void set_code_as_payee::operator()(xact_t& xact)
{
entry_temps.push_back(*xact.entry);
entry_t& entry = entry_temps.back();
entry._date = xact.date();
if (xact.entry->code)
entry.payee = *xact.entry->code;
else
entry.payee = "<none>";
xact_temps.push_back(xact);
xact_t& temp = xact_temps.back();
temp.entry = &entry;
temp.state = xact.state;
temp.add_flags(XACT_TEMP);
entry.add_xact(&temp);
item_handler<xact_t>::operator()(temp);
}
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 (xacts_list::iterator d = days_of_the_week[i].begin();
d != days_of_the_week[i].end();
d++)
subtotal_xacts::operator()(**d);
subtotal_xacts::report_subtotal("%As");
days_of_the_week[i].clear();
}
subtotal_xacts::flush();
}
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 (xacts_list::iterator j = (*i)->xacts.begin();
j != (*i)->xacts.end();
j++)
add_xact((*i)->period, **j);
}
void generate_xacts::add_xact(const interval_t& period,
xact_t& xact)
{
pending_xacts.push_back(pending_xacts_pair(period, &xact));
}
void budget_xacts::report_budget_items(const datetime_t& moment)
{
if (pending_xacts.size() == 0)
return;
bool reported;
do {
reported = false;
for (pending_xacts_list::iterator i = pending_xacts.begin();
i != pending_xacts.end();
i++) {
datetime_t& begin = (*i).first.begin;
if (! is_valid(begin)) {
(*i).first.start(moment);
begin = (*i).first.begin;
}
if (begin < moment &&
(! is_valid((*i).first.end) || begin < (*i).first.end)) {
xact_t& xact = *(*i).second;
DEBUG("ledger.walk.budget", "Reporting budget for "
<< xact_account(xact)->fullname());
#if 0
// jww (2008-04-24): Need a new debug macro here
DEBUG_TIME("ledger.walk.budget", begin);
DEBUG_TIME("ledger.walk.budget", moment);
#endif
entry_temps.push_back(entry_t());
entry_t& entry = entry_temps.back();
entry.payee = "Budget entry";
entry._date = begin;
xact_temps.push_back(xact);
xact_t& temp = xact_temps.back();
temp.entry = &entry;
temp.add_flags(XACT_AUTO | XACT_TEMP);
temp.amount.negate();
entry.add_xact(&temp);
begin = (*i).first.increment(begin);
item_handler<xact_t>::operator()(temp);
reported = true;
}
}
} while (reported);
}
void budget_xacts::operator()(xact_t& xact)
{
bool xact_in_budget = false;
for (pending_xacts_list::iterator i = pending_xacts.begin();
i != pending_xacts.end();
i++)
for (account_t * acct = xact_account(xact);
acct;
acct = acct->parent) {
if (acct == xact_account(*(*i).second)) {
xact_in_budget = true;
// Report the xact as if it had occurred in the parent
// account.
if (xact_account(xact) != acct)
xact_xdata(xact).account = acct;
goto handle;
}
}
handle:
if (xact_in_budget && flags & BUDGET_BUDGETED) {
report_budget_items(xact.date());
item_handler<xact_t>::operator()(xact);
}
else if (! xact_in_budget && flags & BUDGET_UNBUDGETED) {
item_handler<xact_t>::operator()(xact);
}
}
void forecast_xacts::add_xact(const interval_t& period,
xact_t& xact)
{
generate_xacts::add_xact(period, xact);
interval_t& i = pending_xacts.back().first;
if (! is_valid(i.begin)) {
i.start(current_moment);
i.begin = i.increment(i.begin);
} else {
while (i.begin < current_moment)
i.begin = i.increment(i.begin);
}
}
void forecast_xacts::flush()
{
xacts_list passed;
datetime_t last;
while (pending_xacts.size() > 0) {
pending_xacts_list::iterator least = pending_xacts.begin();
for (pending_xacts_list::iterator i = ++pending_xacts.begin();
i != pending_xacts.end();
i++)
if ((*i).first.begin < (*least).first.begin)
least = i;
datetime_t& begin = (*least).first.begin;
if (is_valid((*least).first.end) && begin >= (*least).first.end) {
pending_xacts.erase(least);
passed.remove((*least).second);
continue;
}
xact_t& xact = *(*least).second;
entry_temps.push_back(entry_t());
entry_t& entry = entry_temps.back();
entry.payee = "Forecast entry";
entry._date = begin;
xact_temps.push_back(xact);
xact_t& temp = xact_temps.back();
temp.entry = &entry;
temp.add_flags(XACT_AUTO | XACT_TEMP);
entry.add_xact(&temp);
datetime_t next = (*least).first.increment(begin);
// jww (2008-04-24): Does seconds() here give the total seconds?
if (next < begin || // wraparound
(is_valid(last) && (next - last).seconds() > 365 * 5 * 24 * 3600))
break;
begin = next;
item_handler<xact_t>::operator()(temp);
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 (xacts_list::iterator i = passed.begin();
i != passed.end();
i++)
if (*i == &xact) {
found = true;
break;
}
if (! found) {
passed.push_back(&xact);
if (passed.size() >= pending_xacts.size())
break;
}
}
}
item_handler<xact_t>::flush();
}
template <>
bool compare_items<account_t>::operator()(const account_t * left,
const account_t * right)
{
assert(left);
assert(right);
#if 0
account_xdata_t& lxdata(account_xdata(*left));
if (! (lxdata.dflags & ACCOUNT_SORT_CALC)) {
sort_order.compute(lxdata.sort_value, details_t(*left));
lxdata.dflags |= ACCOUNT_SORT_CALC;
}
account_xdata_t& rxdata(account_xdata(*right));
if (! (rxdata.dflags & ACCOUNT_SORT_CALC)) {
sort_order.compute(rxdata.sort_value, details_t(*right));
rxdata.dflags |= ACCOUNT_SORT_CALC;
}
return lxdata.sort_value < rxdata.sort_value;
#else
return false;
#endif
}
account_xdata_t& account_xdata(const account_t& account)
{
if (! account.data)
account.data = new account_xdata_t();
return *static_cast<account_xdata_t *>(account.data);
}
void sum_accounts(account_t& account)
{
account_xdata_t& xdata(account_xdata(account));
for (accounts_map::iterator i = account.accounts.begin();
i != account.accounts.end();
i++) {
sum_accounts(*(*i).second);
xdata.total += account_xdata_(*(*i).second).total;
xdata.total_count += (account_xdata_(*(*i).second).total_count +
account_xdata_(*(*i).second).count);
}
value_t result;
#if 0
compute_amount(result, details_t(account));
#endif
if (! result.is_realzero())
xdata.total += result;
xdata.total_count += xdata.count;
}
account_t * accounts_iterator::operator()()
{
while (! accounts_i.empty() &&
accounts_i.back() == accounts_end.back()) {
accounts_i.pop_back();
accounts_end.pop_back();
}
if (accounts_i.empty())
return NULL;
account_t * account = (*(accounts_i.back()++)).second;
assert(account);
// If this account has children, queue them up to be iterated next.
if (! account->accounts.empty())
push_back(*account);
return account;
}
void sorted_accounts_iterator::sort_accounts(account_t& account,
accounts_deque_t& deque)
{
for (accounts_map::iterator i = account.accounts.begin();
i != account.accounts.end();
i++)
deque.push_back((*i).second);
std::stable_sort(deque.begin(), deque.end(),
compare_items<account_t>(sort_cmp));
}
account_t * sorted_accounts_iterator::operator()()
{
while (! sorted_accounts_i.empty() &&
sorted_accounts_i.back() == sorted_accounts_end.back()) {
sorted_accounts_i.pop_back();
sorted_accounts_end.pop_back();
assert(! accounts_list.empty());
accounts_list.pop_back();
}
if (sorted_accounts_i.empty())
return NULL;
account_t * account = *sorted_accounts_i.back()++;
assert(account);
// If this account has children, queue them up to be iterated next.
if (! account->accounts.empty())
push_back(*account);
account_xdata(*account).dflags &= ~ACCOUNT_SORT_CALC;
return account;
}
void walk_commodities(commodity_pool_t::commodities_by_ident& commodities,
item_handler<xact_t>& handler)
{
std::list<xact_t> xact_temps;
std::list<entry_t> entry_temps;
std::list<account_t> acct_temps;
for (commodity_pool_t::commodities_by_ident::iterator
i = commodities.begin();
i != commodities.end();
i++) {
if ((*i)->has_flags(COMMODITY_STYLE_NOMARKET))
continue;
entry_temps.push_back(entry_t());
acct_temps.push_back(account_t(NULL, (*i)->symbol()));
if ((*i)->history())
for (commodity_t::history_map::iterator j = (*i)->history()->prices.begin();
j != (*i)->history()->prices.end();
j++) {
entry_temps.back()._date = (*j).first;
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(XACT_TEMP);
entry_temps.back().add_xact(&temp);
handler(xact_temps.back());
}
}
handler.flush();
clear_entries_xacts(entry_temps);
}
void journals_iterator::reset(session_t& session)
{
journals_i = session.journals.begin();
journals_end = session.journals.end();
}
journal_t * journals_iterator::operator()()
{
if (journals_i == journals_end)
return NULL;
return &(*journals_i++);
}
} // namespace ledger