Moved xact_xdata_t into xact_t itself, as a set of "extended data" that might

be gathered during reporting.

Removed the references to accounts and such from the mask logic, which means
that the value expression "acount =~ /foo/" is needed in place of just
"/foo/".
This commit is contained in:
John Wiegley 2008-08-02 22:45:35 -04:00
parent 7b3c8c03c5
commit 5a90fe7357
19 changed files with 386 additions and 386 deletions

7
csv.cc
View file

@ -19,9 +19,8 @@ namespace {
void format_csv_xacts::operator()(xact_t& xact)
{
if (! xact_has_xdata(xact) ||
! (xact_xdata_(xact).dflags & XACT_DISPLAYED)) {
if (! xact.has_xdata() ||
! xact.xdata().has_flags(XACT_EXT_DISPLAYED)) {
{
format_t fmt("%D");
std::ostringstream str;
@ -111,7 +110,7 @@ void format_csv_xacts::operator()(xact_t& xact)
}
out << '\n';
xact_xdata(xact).dflags |= XACT_DISPLAYED;
xact.xdata().add_flags(XACT_EXT_DISPLAYED);
}
}

View file

@ -33,8 +33,8 @@ void format_emacs_xacts::write_entry(entry_t& entry)
void format_emacs_xacts::operator()(xact_t& xact)
{
if (! xact_has_xdata(xact) ||
! (xact_xdata_(xact).dflags & XACT_DISPLAYED)) {
if (! xact.has_xdata() ||
! xact.xdata().has_flags(XACT_EXT_DISPLAYED)) {
if (! last_entry) {
out << "((";
write_entry(*xact.entry);
@ -48,7 +48,7 @@ void format_emacs_xacts::operator()(xact_t& xact)
}
out << " (" << (static_cast<unsigned long>(xact.beg_line) + 1) << " ";
out << "\"" << xact_account(xact)->fullname() << "\" \""
out << "\"" << xact.reported_account()->fullname() << "\" \""
<< xact.amount << "\"";
switch (xact.state) {
@ -71,7 +71,7 @@ void format_emacs_xacts::operator()(xact_t& xact)
last_entry = xact.entry;
xact_xdata(xact).dflags |= XACT_DISPLAYED;
xact.xdata().add_flags(XACT_EXT_DISPLAYED);
}
}

View file

@ -39,8 +39,6 @@ namespace ledger {
class journal_t;
typedef std::list<xact_t *> xacts_list;
class entry_base_t : public supports_flags<>
{
public:
@ -232,6 +230,10 @@ inline bool auto_entry_finalizer_t::operator()(entry_t& entry, bool post) {
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;
} // namespace ledger
#endif // _ENTRY_H

View file

@ -43,10 +43,6 @@ typedef std::list<path> paths_list;
class session_t;
class account_t;
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;
class journal_t : public noncopyable
{
public:

12
mask.h
View file

@ -36,25 +36,17 @@
namespace ledger {
class mask_t : public supports_flags<>
class mask_t
{
mask_t();
public:
#define MASK_SHORT_ACCOUNT 0x01
#define MASK_CODE 0x02
#define MASK_COMMODITY 0x04
#define MASK_PAYEE 0x08
#define MASK_NOTE 0x10
#define MASK_ACCOUNT 0x20
bool exclude;
boost::regex expr;
explicit mask_t(const string& pattern);
mask_t(const mask_t& m)
: supports_flags<>(), exclude(m.exclude), expr(m.expr) {
mask_t(const mask_t& m) : exclude(m.exclude), expr(m.expr) {
TRACE_CTOR(mask_t, "copy");
}
~mask_t() throw() {

28
op.cc
View file

@ -647,34 +647,6 @@ expr_t::ptr_op_t expr_t::op_t::compile(scope_t& scope)
}
return this;
case MASK: {
ptr_op_t match = new op_t(op_t::O_MATCH);
match->set_right(this);
// jww (2008-08-02): Coupling!
ptr_op_t ident = new op_t(op_t::IDENT);
switch (as_mask().flags()) {
case MASK_SHORT_ACCOUNT:
ident->set_ident("account_base");
break;
case MASK_CODE:
ident->set_ident("code");
break;
case MASK_PAYEE:
ident->set_ident("payee");
break;
case MASK_NOTE:
ident->set_ident("note");
break;
case MASK_ACCOUNT:
ident->set_ident("account");
break;
}
match->set_left(ident->compile(scope));
return match;
}
default:
break;
}

View file

@ -50,7 +50,6 @@ expr_t::parser_t::parse_value_term(std::istream& in,
case token_t::MASK:
node = new op_t(op_t::MASK);
node->set_mask(tok.value.as_string());
node->as_mask_lval().add_flags(tok.flags());
break;
case token_t::IDENT: {

View file

@ -46,10 +46,14 @@ class expr_t::parser_t : public noncopyable
#define EXPR_PARSE_NO_ASSIGN 0x08
#define EXPR_PARSE_NO_DATES 0x10
public:
typedef uint_least8_t flags_t;
private:
mutable token_t lookahead;
mutable bool use_lookahead;
token_t& next_token(std::istream& in, token_t::flags_t tflags) const
token_t& next_token(std::istream& in, flags_t tflags) const
{
if (use_lookahead)
use_lookahead = false;
@ -69,10 +73,6 @@ class expr_t::parser_t : public noncopyable
use_lookahead = true;
}
public:
typedef uint_least8_t flags_t;
private:
ptr_op_t parse_value_term(std::istream& in, const flags_t flags) const;
ptr_op_t parse_unary_expr(std::istream& in, const flags_t flags) const;
ptr_op_t parse_mul_expr(std::istream& in, const flags_t flags) const;

18
qif.cc
View file

@ -34,21 +34,21 @@ bool qif_parser_t::test(std::istream& in) const
}
unsigned int qif_parser_t::parse(std::istream& in,
session_t& session,
journal_t& journal,
session_t& session,
journal_t& journal,
account_t * master,
const path * original_file)
{
std::auto_ptr<entry_t> entry;
std::auto_ptr<amount_t> amount;
xact_t * xact;
unsigned int count = 0;
account_t * misc = NULL;
commodity_t * def_commodity = NULL;
bool saw_splits = false;
bool saw_category = false;
xact_t * total = NULL;
xact_t * xact;
unsigned int count = 0;
account_t * misc = NULL;
commodity_t * def_commodity = NULL;
bool saw_splits = false;
bool saw_category = false;
xact_t * total = NULL;
entry.reset(new entry_t);
xact = new xact_t(master);

View file

@ -3,8 +3,8 @@
namespace ledger {
#define xact_next(x) reinterpret_cast<xact_t *>(xact_xdata(*x).ptr)
#define xact_next_ptr(x) reinterpret_cast<xact_t **>(&xact_xdata(*x).ptr)
#define xact_next(x) reinterpret_cast<xact_t *>(x->xdata().ptr)
#define xact_next_ptr(x) reinterpret_cast<xact_t **>(&x->xdata().ptr)
static bool search_for_balance(amount_t& amount,
xact_t ** prev, xact_t * next)

View file

@ -476,8 +476,8 @@ format_xacts::format_xacts(std::ostream& _output_stream,
void format_xacts::operator()(xact_t& xact)
{
if (! xact_has_xdata(xact) ||
! (xact_xdata_(xact).dflags & XACT_DISPLAYED)) {
if (! xact.has_xdata() ||
! xact.xdata().has_flags(XACT_EXT_DISPLAYED)) {
if (last_entry != xact.entry) {
first_line_format.format(output_stream, xact);
last_entry = xact.entry;
@ -489,7 +489,7 @@ void format_xacts::operator()(xact_t& xact)
next_lines_format.format(output_stream, xact);
}
xact_xdata(xact).dflags |= XACT_DISPLAYED;
xact.xdata().add_flags(XACT_EXT_DISPLAYED);
last_xact = &xact;
}
}
@ -515,7 +515,7 @@ void format_entries::format_last_entry()
void format_entries::operator()(xact_t& xact)
{
xact_xdata(xact).dflags |= XACT_TO_DISPLAY;
xact.xdata().add_flags(XACT_EXT_TO_DISPLAY);
if (last_entry && xact.entry != last_entry)
format_last_entry();

View file

@ -1079,7 +1079,7 @@ void write_textual_journal(journal_t& journal,
if (base) {
foreach (xact_t * xact, base->xacts) {
if (! xact->has_flags(XACT_AUTO)) {
xact_xdata(*xact).dflags |= XACT_TO_DISPLAY;
xact->xdata().add_flags(XACT_EXT_TO_DISPLAY);
(*formatter)(*xact);
}
}

View file

@ -53,8 +53,6 @@ void expr_t::token_t::parse_ident(std::istream& in)
kind = IDENT;
length = 0;
clear_flags();
char buf[256];
READ_INTO_(in, buf, 255, c, length,
std::isalnum(c) || c == '_' || c == '.' || c == '-');
@ -122,7 +120,7 @@ void expr_t::token_t::parse_ident(std::istream& in)
value.set_string(buf);
}
void expr_t::token_t::next(std::istream& in, const unsigned int pflags)
void expr_t::token_t::next(std::istream& in, const uint_least8_t pflags)
{
if (in.eof()) {
kind = TOK_EOF;
@ -284,19 +282,6 @@ void expr_t::token_t::next(std::istream& in, const unsigned int pflags)
in.get(c);
length++;
if (short_account_mask)
set_flags(MASK_SHORT_ACCOUNT);
else if (code_mask)
set_flags(MASK_CODE);
else if (commodity_mask)
set_flags(MASK_COMMODITY);
else if (payee_mask)
set_flags(MASK_PAYEE);
else if (note_mask)
set_flags(MASK_NOTE);
else
set_flags(MASK_ACCOUNT);
kind = MASK;
value.set_string(buf);
break;

View file

@ -36,7 +36,7 @@
namespace ledger {
struct expr_t::token_t : public noncopyable, public supports_flags<>
struct expr_t::token_t : public noncopyable
{
enum kind_t {
VALUE, // any kind of literal value
@ -79,7 +79,7 @@ struct expr_t::token_t : public noncopyable, public supports_flags<>
value_t value;
std::size_t length;
explicit token_t() : supports_flags<>(), kind(UNKNOWN), length(0) {
explicit token_t() : kind(UNKNOWN), length(0) {
TRACE_CTOR(token_t, "");
}
~token_t() throw() {
@ -104,7 +104,7 @@ struct expr_t::token_t : public noncopyable, public supports_flags<>
}
void parse_ident(std::istream& in);
void next(std::istream& in, unsigned int flags);
void next(std::istream& in, const uint_least8_t flags);
void rewind(std::istream& in);
void unexpected();

165
walk.cc
View file

@ -8,24 +8,23 @@
namespace ledger {
template <>
bool compare_items<xact_t>::operator()(const xact_t * left,
const xact_t * right)
bool compare_items<xact_t>::operator()(xact_t * left, xact_t * right)
{
assert(left);
assert(right);
xact_xdata_t& lxdata(xact_xdata(*left));
if (! (lxdata.dflags & XACT_SORT_CALC)) {
lxdata.sort_value = sort_order.calc(const_cast<xact_t&>(*left));
xact_t::xdata_t& lxdata(left->xdata());
if (! lxdata.has_flags(XACT_EXT_SORT_CALC)) {
lxdata.sort_value = sort_order.calc(*left);
lxdata.sort_value.reduce();
lxdata.dflags |= XACT_SORT_CALC;
lxdata.add_flags(XACT_EXT_SORT_CALC);
}
xact_xdata_t& rxdata(xact_xdata(*right));
if (! (rxdata.dflags & XACT_SORT_CALC)) {
rxdata.sort_value = sort_order.calc(const_cast<xact_t&>(*right));
xact_t::xdata_t& rxdata(right->xdata());
if (! rxdata.has_flags(XACT_EXT_SORT_CALC)) {
rxdata.sort_value = sort_order.calc(*right);
rxdata.sort_value.reduce();
rxdata.dflags |= XACT_SORT_CALC;
rxdata.add_flags(XACT_EXT_SORT_CALC);
}
DEBUG("ledger.walk.compare_items_xact",
@ -36,27 +35,6 @@ bool compare_items<xact_t>::operator()(const xact_t * left,
return lxdata.sort_value < rxdata.sort_value;
}
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();
@ -157,11 +135,11 @@ void truncate_entries::flush()
void set_account_value::operator()(xact_t& xact)
{
account_t * acct = xact_account(xact);
account_t * acct = xact.reported_account();
assert(acct);
account_xdata_t& xdata = account_xdata(*acct);
add_xact_to(xact, xdata.value);
xact.add_to_value(xdata.value);
xdata.count++;
if (xact.has_flags(XACT_VIRTUAL))
@ -176,7 +154,7 @@ void sort_xacts::post_accumulated_xacts()
compare_items<xact_t>(sort_order));
foreach (xact_t * xact, xacts) {
xact_xdata(*xact).dflags &= ~XACT_SORT_CALC;
xact->xdata().drop_flags(XACT_EXT_SORT_CALC);
item_handler<xact_t>::operator()(*xact);
}
@ -186,26 +164,24 @@ void sort_xacts::post_accumulated_xacts()
void calc_xacts::operator()(xact_t& xact)
{
try {
xact_t::xdata_t& xdata(xact.xdata());
xact_xdata_t& xdata(xact_xdata(xact));
if (last_xact && last_xact->has_xdata()) {
if (xdata.total.is_null())
xdata.total = last_xact->xdata().total;
else
xdata.total += last_xact->xdata().total;
xdata.index = last_xact->xdata().index + 1;
} else {
xdata.index = 0;
}
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.has_flags(XACT_EXT_NO_TOTAL))
xact.add_to_value(xdata.total);
if (! (xdata.dflags & XACT_NO_TOTAL))
add_xact_to(xact, xdata.total);
item_handler<xact_t>::operator()(xact);
last_xact = &xact;
item_handler<xact_t>::operator()(xact);
last_xact = &xact;
}
catch (const std::exception& err) {
add_error_context("Calculating transaction at");
@ -218,9 +194,9 @@ void calc_xacts::operator()(xact_t& xact)
void invert_xacts::operator()(xact_t& xact)
{
if (xact_has_xdata(xact) &&
xact_xdata_(xact).dflags & XACT_COMPOUND) {
xact_xdata_(xact).value.negate();
if (xact.has_xdata() &&
xact.xdata().has_flags(XACT_EXT_COMPOUND)) {
xact.xdata().value.negate();
} else {
xact.amount.negate();
if (xact.cost)
@ -251,7 +227,7 @@ void handle_value(const value_t& value,
// temporary, do so now.
if (component_xacts)
xact_xdata(xact).copy_component_xacts(*component_xacts);
xact.xdata().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
@ -264,7 +240,7 @@ void handle_value(const value_t& value,
xact.add_flags(XACT_BALANCE);
}
xact_xdata_t& xdata(xact_xdata(xact));
xact_t::xdata_t& xdata(xact.xdata());
if (is_valid(date))
xdata.date = date;
@ -286,7 +262,7 @@ void handle_value(const value_t& value,
case value_t::BALANCE:
case value_t::BALANCE_PAIR:
xdata.value = temp;
flags |= XACT_COMPOUND;
flags |= XACT_EXT_COMPOUND;
break;
default:
@ -295,7 +271,7 @@ void handle_value(const value_t& value,
}
if (flags)
xdata.dflags |= flags;
xdata.add_flags(flags);
handler(xact);
}
@ -330,7 +306,7 @@ void collapse_xacts::operator()(xact_t& xact)
if (last_entry && last_entry != xact.entry && count > 0)
report_subtotal();
add_xact_to(xact, subtotal);
xact.add_to_value(subtotal);
count++;
last_entry = xact.entry;
@ -343,12 +319,12 @@ void related_xacts::flush()
foreach (xact_t * xact, xacts) {
if (xact->entry) {
foreach (xact_t * r_xact, xact->entry->xacts) {
xact_xdata_t& xdata = xact_xdata(*r_xact);
if (! (xdata.dflags & XACT_HANDLED) &&
(! (xdata.dflags & XACT_RECEIVED) ?
xact_t::xdata_t& xdata(r_xact->xdata());
if (! xdata.has_flags(XACT_EXT_HANDLED) &&
(! xdata.has_flags(XACT_EXT_RECEIVED) ?
! r_xact->has_flags(XACT_AUTO | XACT_VIRTUAL) :
also_matching)) {
xdata.dflags |= XACT_HANDLED;
xdata.add_flags(XACT_EXT_HANDLED);
item_handler<xact_t>::operator()(*r_xact);
}
}
@ -356,10 +332,10 @@ void related_xacts::flush()
// 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(*xact);
if (! (xdata.dflags & XACT_HANDLED) &&
xact_t::xdata_t& xdata(xact->xdata());
if (! xdata.has_flags(XACT_EXT_HANDLED) &&
! xact->has_flags(XACT_AUTO)) {
xdata.dflags |= XACT_HANDLED;
xdata.add_flags(XACT_EXT_HANDLED);
item_handler<xact_t>::operator()(*xact);
}
}
@ -373,7 +349,7 @@ void changed_value_xacts::output_diff(const date_t& date)
{
value_t cur_bal;
xact_xdata(*last_xact).date = date;
last_xact->xdata().date = date;
#if 0
compute_total(cur_bal, details_t(*last_xact));
#endif
@ -381,7 +357,7 @@ void changed_value_xacts::output_diff(const date_t& date)
#if 0
// jww (2008-04-24): What does this do?
xact_xdata(*last_xact).date = 0;
last_xact->xdata().date = 0;
#endif
if (value_t diff = cur_bal - last_balance) {
@ -390,24 +366,18 @@ void changed_value_xacts::output_diff(const date_t& date)
entry.payee = "Commodities revalued";
entry._date = date;
handle_value(diff, NULL, &entry, XACT_NO_TOTAL, xact_temps,
handle_value(diff, NULL, &entry, XACT_EXT_NO_TOTAL, xact_temps,
*handler);
}
}
void changed_value_xacts::operator()(xact_t& xact)
{
if (last_xact) {
date_t date;
if (xact_has_xdata(*last_xact))
date = xact_xdata_(*last_xact).date;
else
date = xact.date();
output_diff(date);
}
if (last_xact)
output_diff(last_xact->reported_date());
if (changed_values_only)
xact_xdata(xact).dflags |= XACT_DISPLAYED;
xact.xdata().add_flags(XACT_EXT_DISPLAYED);
item_handler<xact_t>::operator()(xact);
@ -422,9 +392,13 @@ void changed_value_xacts::operator()(xact_t& 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);
if (xact.has_xdata() &&
xact.xdata().has_component_xacts())
#if 0
xact.xdata().walk_component_xacts(*handler);
#else
;
#endif
else
(*handler)(xact);
}
@ -460,13 +434,13 @@ void subtotal_xacts::operator()(xact_t& xact)
if (! is_valid(finish) || xact.date() > finish)
finish = xact.date();
account_t * acct = xact_account(xact);
account_t * acct = xact.reported_account();
assert(acct);
values_map::iterator i = values.find(acct->fullname());
if (i == values.end()) {
value_t temp;
add_xact_to(xact, temp);
xact.add_to_value(temp);
std::pair<values_map::iterator, bool> result
= values.insert(values_pair(acct->fullname(), acct_value_t(acct, temp)));
assert(result.second);
@ -474,7 +448,7 @@ void subtotal_xacts::operator()(xact_t& xact)
if (remember_components)
(*result.first).second.components.push_back(&xact);
} else {
add_xact_to(xact, (*i).second.value);
xact.add_to_value((*i).second.value);
if (remember_components)
(*i).second.components.push_back(&xact);
@ -485,9 +459,9 @@ void subtotal_xacts::operator()(xact_t& xact)
// that contain only virtual xacts.
if (! xact.has_flags(XACT_VIRTUAL))
account_xdata(*xact_account(xact)).dflags |= ACCOUNT_HAS_NON_VIRTUALS;
account_xdata(*xact.reported_account()).dflags |= ACCOUNT_HAS_NON_VIRTUALS;
else if (! xact.has_flags(XACT_BALANCE))
account_xdata(*xact_account(xact)).dflags |= ACCOUNT_HAS_UNB_VIRTUALS;
account_xdata(*xact.reported_account()).dflags |= ACCOUNT_HAS_UNB_VIRTUALS;
}
void interval_xacts::report_subtotal(const date_t& date)
@ -675,7 +649,7 @@ void budget_xacts::report_budget_items(const date_t& date)
xact_t& xact = *pair.second;
DEBUG("ledger.walk.budget", "Reporting budget for "
<< xact_account(xact)->fullname());
<< xact.reported_account()->fullname());
entry_temps.push_back(entry_t());
entry_t& entry = entry_temps.back();
@ -704,15 +678,15 @@ void budget_xacts::operator()(xact_t& xact)
bool xact_in_budget = false;
foreach (pending_xacts_list::value_type& pair, pending_xacts)
for (account_t * acct = xact_account(xact);
for (account_t * acct = xact.reported_account();
acct;
acct = acct->parent) {
if (acct == xact_account(*pair.second)) {
if (acct == (*pair.second).reported_account()) {
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;
if (xact.reported_account() != acct)
xact.xdata().account = acct;
goto handle;
}
}
@ -782,8 +756,8 @@ void forecast_xacts::flush()
item_handler<xact_t>::operator()(temp);
if (xact_has_xdata(temp) &&
xact_xdata_(temp).dflags & XACT_MATCHES) {
if (temp.has_xdata() &&
temp.xdata().has_flags(XACT_EXT_MATCHES)) {
if (! pred(temp))
break;
last = temp.date();
@ -808,21 +782,20 @@ void forecast_xacts::flush()
}
template <>
bool compare_items<account_t>::operator()(const account_t * left,
const account_t * right)
bool compare_items<account_t>::operator()(account_t * left, account_t * right)
{
assert(left);
assert(right);
account_xdata_t& lxdata(account_xdata(*left));
if (! (lxdata.dflags & ACCOUNT_SORT_CALC)) {
lxdata.sort_value = sort_order.calc(const_cast<account_t&>(*left));
lxdata.sort_value = sort_order.calc(*left);
lxdata.dflags |= ACCOUNT_SORT_CALC;
}
account_xdata_t& rxdata(account_xdata(*right));
if (! (rxdata.dflags & ACCOUNT_SORT_CALC)) {
rxdata.sort_value = sort_order.calc(const_cast<account_t&>(*right));
rxdata.sort_value = sort_order.calc(*right);
rxdata.dflags |= ACCOUNT_SORT_CALC;
}

223
walk.h
View file

@ -2,6 +2,7 @@
#define _WALK_H
#include "journal.h"
#include "entry.h"
#include "account.h"
namespace ledger {
@ -34,123 +35,6 @@ public:
typedef shared_ptr<item_handler<xact_t> > xact_handler_ptr;
template <typename T>
class compare_items
{
expr_t sort_order;
compare_items();
public:
compare_items(const compare_items& other) : sort_order(other.sort_order) {
TRACE_CTOR(compare_items, "copy");
}
compare_items(const expr_t& _sort_order) : sort_order(_sort_order) {
TRACE_CTOR(compare_items, "const value_expr&");
}
~compare_items() throw() {
TRACE_DTOR(compare_items);
}
bool operator()(const T * left, const T * right);
};
template <typename T>
bool compare_items<T>::operator()(const T * left, const T * right)
{
assert(left);
assert(right);
return sort_order.calc(*left) < sort_order.calc(*right);
}
template <>
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);
//////////////////////////////////////////////////////////////////////
//
// Xact handlers
//
#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 xact_xdata_t : public noncopyable
{
value_t total;
value_t sort_value;
value_t value;
unsigned int index;
unsigned short dflags;
date_t date;
account_t * account;
void * ptr;
xacts_list * component_xacts;
xact_xdata_t()
: index(0), dflags(0),
account(NULL), ptr(NULL), component_xacts(NULL) {
TRACE_CTOR(xact_xdata_t, "");
}
~xact_xdata_t() {
TRACE_DTOR(xact_xdata_t);
if (component_xacts)
checked_delete(component_xacts);
}
void remember_xact(xact_t& xact) {
if (! component_xacts)
component_xacts = new xacts_list;
component_xacts->push_back(&xact);
}
bool have_component_xacts() const {
return component_xacts != NULL && ! component_xacts->empty();
}
void copy_component_xacts(xacts_list& xacts) {
foreach (xact_t * xact, xacts)
remember_xact(*xact);
}
void walk_component_xacts(item_handler<xact_t>& handler) const {
foreach (xact_t * xact, *component_xacts)
handler(*xact);
}
};
inline bool xact_has_xdata(const xact_t& xact) {
return xact.data != NULL;
}
inline xact_xdata_t& xact_xdata_(const xact_t& xact) {
return *static_cast<xact_xdata_t *>(xact.data);
}
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(xact_t& xact) {
if (xact.data) {
account_t * account = xact_xdata(xact).account;
if (account)
return account;
}
return xact.account;
}
inline const account_t * xact_account(const xact_t& xact) {
return xact_account(const_cast<xact_t&>(xact));
}
//////////////////////////////////////////////////////////////////////
class entries_iterator : public noncopyable
@ -226,7 +110,7 @@ public:
class session_xacts_iterator : public xacts_iterator
{
entries_iterator entries;
entries_iterator entries;
entry_xacts_iterator xacts;
public:
@ -258,10 +142,7 @@ class clear_xact_xdata : public item_handler<xact_t>
{
public:
virtual void operator()(xact_t& xact) {
if (xact.data) {
checked_delete(static_cast<xact_xdata_t *>(xact.data));
xact.data = NULL;
}
xact.clear_xdata();
}
};
@ -270,11 +151,11 @@ class pass_down_xacts : public item_handler<xact_t>
pass_down_xacts();
public:
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");
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);
}
@ -284,6 +165,25 @@ public:
}
};
class push_to_xacts_list : public item_handler<xact_t>
{
push_to_xacts_list();
public:
xacts_list& xacts;
push_to_xacts_list(xacts_list& _xacts) : xacts(_xacts) {
TRACE_CTOR(push_to_xacts_list, "xacts_list&");
}
virtual ~push_to_xacts_list() {
TRACE_DTOR(push_to_xacts_list);
}
virtual void operator()(xact_t& xact) {
xacts.push_back(&xact);
}
};
class truncate_entries : public item_handler<xact_t>
{
int head_count;
@ -306,6 +206,9 @@ public:
virtual void flush();
virtual void operator()(xact_t& xact) {
if (tail_count == 0 && head_count > 0 &&
xacts.size() >= static_cast<unsigned int>(head_count))
return;
xacts.push_back(&xact);
}
};
@ -319,26 +222,6 @@ public:
virtual void operator()(xact_t& xact);
};
class push_to_xacts_list : public item_handler<xact_t>
{
push_to_xacts_list();
public:
xacts_list& xact_list;
push_to_xacts_list(xacts_list& _xact_list)
: xact_list(_xact_list) {
TRACE_CTOR(push_to_xacts_list, "xacts_list&");
}
virtual ~push_to_xacts_list() {
TRACE_DTOR(push_to_xacts_list);
}
virtual void operator()(xact_t& xact) {
xact_list.push_back(&xact);
}
};
class sort_xacts : public item_handler<xact_t>
{
typedef std::deque<xact_t *> xacts_deque;
@ -444,7 +327,7 @@ public:
virtual void operator()(xact_t& xact) {
if (pred(xact)) {
xact_xdata(xact).dflags |= XACT_MATCHES;
xact.xdata().add_flags(XACT_EXT_MATCHES);
(*handler)(xact);
}
}
@ -567,7 +450,7 @@ public:
virtual void flush();
virtual void operator()(xact_t& xact) {
xact_xdata(xact).dflags |= XACT_RECEIVED;
xact.xdata().add_flags(XACT_EXT_RECEIVED);
xacts.push_back(&xact);
}
};
@ -577,12 +460,12 @@ class changed_value_xacts : public item_handler<xact_t>
// This filter requires that calc_xacts be used at some point
// later in the chain.
bool changed_values_only;
bool changed_values_only;
xact_t * last_xact;
value_t last_balance;
value_t last_balance;
std::list<entry_t> entry_temps;
std::list<xact_t> xact_temps;
std::list<entry_t> entry_temps;
std::list<xact_t> xact_temps;
changed_value_xacts();
@ -1045,6 +928,40 @@ public:
virtual journal_t * operator()();
};
template <typename T>
class compare_items
{
expr_t sort_order;
compare_items();
public:
compare_items(const compare_items& other) : sort_order(other.sort_order) {
TRACE_CTOR(compare_items, "copy");
}
compare_items(const expr_t& _sort_order) : sort_order(_sort_order) {
TRACE_CTOR(compare_items, "const value_expr&");
}
~compare_items() throw() {
TRACE_DTOR(compare_items);
}
bool operator()(T * left, T * right);
};
template <typename T>
bool compare_items<T>::operator()(T * left, T * right)
{
assert(left);
assert(right);
return sort_order.calc(*left) < sort_order.calc(*right);
}
template <>
bool compare_items<xact_t>::operator()(xact_t * left, xact_t * right);
template <>
bool compare_items<account_t>::operator()(account_t * left,
account_t * right);
} // namespace ledger
#endif // _WALK_H

98
xact.cc
View file

@ -58,18 +58,39 @@ date_t xact_t::effective_date() const
}
namespace {
value_t get_amount(xact_t& xact)
{
return xact.amount;
value_t get_state(xact_t& xact) {
return long(xact.state);
}
value_t get_date(xact_t& xact)
{
value_t state_uncleared(call_scope_t&) {
return 0L;
}
value_t state_cleared(call_scope_t&) {
return 1L;
}
value_t state_pending(call_scope_t&) {
return 2L;
}
value_t get_date(xact_t& xact) {
return xact.date();
}
value_t get_account(call_scope_t& scope)
{
value_t get_amount(xact_t& xact) {
return xact.amount;
}
value_t get_cost(xact_t& xact) {
return xact.cost ? *xact.cost : xact.amount;
}
value_t get_note(xact_t& xact) {
return string_value(xact.note ? *xact.note : ":NOTELESS:");
}
value_t get_account(call_scope_t& scope) {
xact_t& xact(downcast<xact_t>(*scope.parent));
long width = 0;
@ -78,7 +99,7 @@ namespace {
// jww (2008-08-02): Accept a width here so that we can abbreviate the
// string.
string name = xact.account->fullname();
string name = xact.reported_account()->fullname();
if (width > 2)
name = format_t::truncate(name, width - 2, true);
@ -92,10 +113,33 @@ namespace {
return string_value(name);
}
value_t get_account_base(xact_t& xact)
{
assert(false);
return NULL_VALUE;
value_t get_account_base(xact_t& xact) {
return string_value(xact.reported_account()->name);
}
value_t get_beg_pos(xact_t& xact) {
return long(xact.beg_pos);
}
value_t get_beg_line(xact_t& xact) {
return long(xact.beg_line);
}
value_t get_end_pos(xact_t& xact) {
return long(xact.end_pos);
}
value_t get_end_line(xact_t& xact) {
return long(xact.end_line);
}
// xdata_t members...
value_t get_total(xact_t& xact) {
if (xact.xdata_)
return xact.xdata_->total;
else
return xact.amount;
}
template <value_t (*Func)(xact_t&)>
@ -115,16 +159,33 @@ expr_t::ptr_op_t xact_t::lookup(const string& name)
else if (name == "account_base")
return WRAP_FUNCTOR(get_wrapper<&get_account_base>);
break;
case 'c':
if (name == "cleared")
return expr_t::op_t::wrap_value(0L);
break;
case 'd':
if (name[1] == '\0' || name == "date")
return WRAP_FUNCTOR(get_wrapper<&get_date>);
break;
case 'f':
if (name.find("fmt_") == 0) {
if (name == "fmt_A")
return WRAP_FUNCTOR(get_account);
}
break;
case 'p':
if (name == "pending")
return expr_t::op_t::wrap_value(2L);
break;
case 'u':
if (name == "uncleared")
return expr_t::op_t::wrap_value(1L);
break;
}
return entry->lookup(name);
}
@ -187,4 +248,17 @@ xact_context::xact_context(const xact_t& _xact, const string& desc) throw()
}
#endif
void xact_t::add_to_value(value_t& value)
{
if (xdata_ && xdata_->has_flags(XACT_EXT_COMPOUND)) {
value += xdata_->value;
}
else if (cost || (! value.is_null() && ! value.is_realzero())) {
value.add(amount, cost);
}
else {
value = amount;
}
}
} // namespace ledger

140
xact.h
View file

@ -37,7 +37,15 @@
namespace ledger {
// These flags persist with the object
class entry_t;
class account_t;
class xact_t;
typedef std::list<xact_t *> xacts_list;
class xact_t : public supports_flags<>, public scope_t
{
public:
#define XACT_NORMAL 0x0000 // no flags at all, a basic transaction
#define XACT_VIRTUAL 0x0001 // the account was specified with (parens)
#define XACT_BALANCE 0x0002 // the account was specified with [brackets]
@ -47,47 +55,42 @@ namespace ledger {
#define XACT_GENERATED 0x0020 // transaction was not found in a journal
#define XACT_TEMP 0x0040 // transaction is a temporary object
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;
state_t state;
optional<date_t> _date;
optional<date_t> _date_eff;
optional<string> note;
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;
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)
flags_t _flags = XACT_NORMAL)
: supports_flags<>(_flags), entry(NULL), account(_account),
state(UNCLEARED), beg_pos(0), beg_line(0), end_pos(0), end_line(0)
{
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)
const amount_t& _amount,
flags_t _flags = XACT_NORMAL,
const optional<string>& _note = none)
: supports_flags<>(_flags), entry(NULL), account(_account),
state(UNCLEARED), note(_note), amount(_amount),
beg_pos(0), beg_line(0), end_pos(0), end_line(0)
{
TRACE_CTOR(xact_t,
"account_t *, const amount_t&, flags_t, const string&");
@ -96,18 +99,18 @@ class xact_t : public supports_flags<>, public scope_t
: supports_flags<>(xact),
scope_t(),
entry(xact.entry),
state(xact.state),
account(xact.account),
state(xact.state),
_date(xact._date),
_date_eff(xact._date_eff),
note(xact.note),
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?
xdata_(xact.xdata_) // jww (2008-07-19): What are the copy semantics?
{
TRACE_CTOR(xact_t, "copy");
}
@ -129,6 +132,95 @@ class xact_t : public supports_flags<>, public scope_t
virtual expr_t::ptr_op_t lookup(const string& name);
bool valid() const;
struct xdata_t : public supports_flags<>
{
#define XACT_EXT_RECEIVED 0x01
#define XACT_EXT_HANDLED 0x02
#define XACT_EXT_TO_DISPLAY 0x04
#define XACT_EXT_DISPLAYED 0x08
#define XACT_EXT_NO_TOTAL 0x10
#define XACT_EXT_SORT_CALC 0x20
#define XACT_EXT_COMPOUND 0x40
#define XACT_EXT_MATCHES 0x80
value_t total;
value_t sort_value;
value_t value;
unsigned int index;
date_t date;
account_t * account;
void * ptr;
optional<xacts_list> component_xacts;
xdata_t() : supports_flags<>(), index(0), account(NULL), ptr(NULL) {
TRACE_CTOR(xdata_t, "");
}
~xdata_t() throw() {
TRACE_DTOR(xdata_t);
}
void remember_xact(xact_t& xact) {
if (! component_xacts)
component_xacts = xacts_list();
component_xacts->push_back(&xact);
}
bool has_component_xacts() const {
return component_xacts && ! component_xacts->empty();
}
void copy_component_xacts(xacts_list& xacts) {
foreach (xact_t * xact, xacts)
remember_xact(*xact);
}
#if 0
void walk_component_xacts(item_handler<xact_t>& handler) const {
foreach (xact_t * xact, *component_xacts)
handler(*xact);
}
#endif
};
// This variable holds a pointer to "extended data" which is usually
// produced only during reporting, and only for the transaction set being
// reported. It's a memory-saving measure to delay allocation until the
// last possible moment.
mutable optional<xdata_t> xdata_;
bool has_xdata() const {
return xdata_;
}
void clear_xdata() {
xdata_ = none;
}
xdata_t& xdata() {
if (! xdata_)
xdata_ = xdata_t();
return *xdata_;
}
void add_to_value(value_t& value);
date_t reported_date() const {
if (xdata_ && is_valid(xdata_->date))
return xdata_->date;
return
date();
}
account_t * reported_account() {
if (xdata_)
if (account_t * acct = xdata_->account)
return acct;
return account;
}
const account_t * reported_account() const {
return const_cast<xact_t *>(this)->reported_account();
}
};
} // namespace ledger

15
xml.cc
View file

@ -381,9 +381,9 @@ void format_xml_entries::format_last_entry()
}
bool first = true;
foreach (const xact_t * xact, last_entry->xacts) {
if (xact_has_xdata(*xact) &&
xact_xdata_(*xact).dflags & XACT_TO_DISPLAY) {
foreach (xact_t * xact, last_entry->xacts) {
if (xact->has_xdata() &&
xact->xdata().has_flags(XACT_EXT_TO_DISPLAY)) {
if (first) {
output_stream << " <en:xacts>\n";
first = false;
@ -427,9 +427,8 @@ void format_xml_entries::format_last_entry()
}
output_stream << " <tr:amount>\n";
if (xact_xdata_(*xact).dflags & XACT_COMPOUND)
xml_write_value(output_stream,
xact_xdata_(*xact).value, 10);
if (xact->xdata().has_flags(XACT_EXT_COMPOUND))
xml_write_value(output_stream, xact->xdata().value, 10);
else
xml_write_value(output_stream, value_t(xact->amount), 10);
output_stream << " </tr:amount>\n";
@ -448,13 +447,13 @@ void format_xml_entries::format_last_entry()
if (show_totals) {
output_stream << " <total>\n";
xml_write_value(output_stream, xact_xdata_(*xact).total, 10);
xml_write_value(output_stream, xact->xdata().total, 10);
output_stream << " </total>\n";
}
output_stream << " </xact>\n";
xact_xdata_(*xact).dflags |= XACT_DISPLAYED;
xact->xdata().add_flags(XACT_EXT_DISPLAYED);
}
}