Added new --descend option.

This commit is contained in:
John Wiegley 2006-03-12 03:06:11 +00:00
parent 49ae3b65d5
commit 4f83a2bf8f
6 changed files with 190 additions and 29 deletions

View file

@ -76,6 +76,8 @@ void config_t::reset()
secondary_predicate = "";
display_predicate = "";
descend_expr = "";
head_entries = 0;
tail_entries = 0;
@ -322,6 +324,8 @@ config_t::chain_xact_handlers(const std::string& command,
account_t * master,
std::list<item_handler<transaction_t> *>& ptrs)
{
bool remember_components = false;
item_handler<transaction_t> * formatter = NULL;
ptrs.push_back(formatter = base_formatter);
@ -348,6 +352,30 @@ config_t::chain_xact_handlers(const std::string& command,
// transactions are included or excluded from the running total.
ptrs.push_back(formatter = new calc_transactions(formatter));
// component_transactions looks for reported transaction that
// match the given `descend_expr', and then reports the
// transactions which made up the total for that reported
// transaction.
if (! descend_expr.empty()) {
std::list<std::string> descend_exprs;
std::string::size_type beg = 0;
for (std::string::size_type pos = descend_expr.find(';');
pos != std::string::npos;
beg = pos + 1, pos = descend_expr.find(';', beg))
descend_exprs.push_back(std::string(descend_expr, beg, pos));
descend_exprs.push_back(std::string(descend_expr, beg));
for (std::list<std::string>::reverse_iterator i =
descend_exprs.rbegin();
i != descend_exprs.rend();
i++)
ptrs.push_back(formatter =
new component_transactions(formatter, *i));
remember_components = true;
}
// reconcile_transactions will pass through only those
// transactions which can be reconciled to a given balance
// (calculated against the transactions which it receives).
@ -400,18 +428,22 @@ config_t::chain_xact_handlers(const std::string& command,
// reports all the transactions that fall on each subsequent day
// of the week.
if (show_subtotal && ! (command == "b" || command == "E"))
ptrs.push_back(formatter = new subtotal_transactions(formatter));
ptrs.push_back(formatter =
new subtotal_transactions(formatter, remember_components));
if (days_of_the_week)
ptrs.push_back(formatter = new dow_transactions(formatter));
ptrs.push_back(formatter =
new dow_transactions(formatter, remember_components));
else if (by_payee)
ptrs.push_back(formatter = new by_payee_transactions(formatter));
ptrs.push_back(formatter =
new by_payee_transactions(formatter, remember_components));
if (! report_period.empty()) {
ptrs.push_back(formatter =
new interval_transactions(formatter,
report_period,
report_period_sort));
report_period_sort,
remember_components));
ptrs.push_back(formatter = new sort_transactions(formatter, "d"));
}
@ -927,6 +959,23 @@ OPT_BEGIN(related, "r") {
config->show_related = true;
} OPT_END(related);
OPT_BEGIN(descend, "") {
std::string arg(optarg);
std::string::size_type beg = 0;
config->descend_expr = "";
for (std::string::size_type pos = arg.find(';');
pos != std::string::npos;
beg = pos + 1, pos = arg.find(';', beg))
config->descend_expr += (std::string("t=={") +
std::string(arg, beg, pos) + "};");
config->descend_expr += (std::string("t=={") +
std::string(arg, beg) + "}");
} OPT_END(descend);
OPT_BEGIN(descend_if, "") {
config->descend_expr = optarg;
} OPT_END(descend_if);
OPT_BEGIN(period, "p:") {
if (config->report_period.empty()) {
config->report_period = optarg;
@ -1157,6 +1206,8 @@ option_t config_options[CONFIG_OPTIONS_SIZE] = {
{ "current", 'c', false, opt_current, false },
{ "date-format", 'y', true, opt_date_format, false },
{ "debug", '\0', true, opt_debug, false },
{ "descend", '\0', true, opt_descend, false },
{ "descend-if", '\0', true, opt_descend_if, false },
{ "deviation", 'D', false, opt_deviation, false },
{ "display", 'd', true, opt_display, false },
{ "dow", '\0', false, opt_dow, false },

View file

@ -44,6 +44,7 @@ class config_t
std::string sort_string;
std::string amount_expr;
std::string total_expr;
std::string descend_expr;
std::string forecast_limit;
std::string reconcile_balance;
std::string reconcile_date;
@ -106,7 +107,7 @@ class config_t
std::list<item_handler<transaction_t> *>& ptrs);
};
#define CONFIG_OPTIONS_SIZE 84
#define CONFIG_OPTIONS_SIZE 86
extern option_t config_options[CONFIG_OPTIONS_SIZE];
void option_help(std::ostream& out);

View file

@ -1578,6 +1578,17 @@ bool write_value_expr(std::ostream& out,
case value_expr_t::COST_TOTAL: out << "total_cost"; break;
case value_expr_t::F_NOW: out << "now"; break;
case value_expr_t::VALUE_EXPR:
if (write_value_expr(out, amount_expr->parsed,
node_to_find, start_pos, end_pos))
found = true;
break;
case value_expr_t::TOTAL_EXPR:
if (write_value_expr(out, total_expr->parsed,
node_to_find, start_pos, end_pos))
found = true;
break;
case value_expr_t::F_ARITH_MEAN:
out << "average(";
if (write_value_expr(out, node->left, node_to_find, start_pos, end_pos))
@ -1883,6 +1894,9 @@ void dump_value_expr(std::ostream& out, const value_expr_t * node,
case value_expr_t::PRICE_TOTAL: out << "PRICE_TOTAL"; break;
case value_expr_t::COST_TOTAL: out << "COST_TOTAL"; break;
case value_expr_t::VALUE_EXPR: out << "VALUE_EXPR"; break;
case value_expr_t::TOTAL_EXPR: out << "TOTAL_EXPR"; break;
case value_expr_t::F_NOW: out << "F_NOW"; break;
case value_expr_t::F_ARITH_MEAN: out << "F_ARITH_MEAN"; break;
case value_expr_t::F_ABS: out << "F_ABS"; break;

View file

@ -427,6 +427,12 @@ public:
guarded_compute(parsed, temp, details, context);
return temp;
}
friend bool write_value_expr(std::ostream& out,
const value_expr_t * node,
const value_expr_t * node_to_find,
unsigned long * start_pos,
unsigned long * end_pos);
};
extern std::auto_ptr<value_expr> amount_expr;

38
walk.cc
View file

@ -181,7 +181,8 @@ void handle_value(const value_t& value,
unsigned int flags,
std::list<transaction_t>& temps,
item_handler<transaction_t>& handler,
const std::time_t date = 0)
const std::time_t date = 0,
transactions_list * component_xacts = NULL)
{
temps.push_back(transaction_t(account));
transaction_t& xact(temps.back());
@ -189,6 +190,12 @@ void handle_value(const value_t& value,
xact.flags |= TRANSACTION_BULK_ALLOC;
entry->add_transaction(&xact);
// If there are component transactions to associate with this
// temporary, do so now.
if (component_xacts)
transaction_xdata(xact).copy_component_xacts(*component_xacts);
// If the account for this transaction is all virtual, then report
// the transaction as such. This allows subtotal reports to show
// "(Account)" for accounts that contain only virtual transactions.
@ -343,6 +350,17 @@ void changed_value_transactions::operator()(transaction_t& xact)
last_xact = &xact;
}
void component_transactions::operator()(transaction_t& xact)
{
if (handler && pred(xact)) {
if (transaction_has_xdata(xact) &&
transaction_xdata_(xact).have_component_xacts())
transaction_xdata_(xact).walk_component_xacts(*handler);
else
(*handler)(xact);
}
}
void subtotal_transactions::report_subtotal(const char * spec_fmt)
{
char buf[256];
@ -364,7 +382,7 @@ void subtotal_transactions::report_subtotal(const char * spec_fmt)
i != values.end();
i++)
handle_value((*i).second.value, (*i).second.account, &entry, 0,
xact_temps, *handler, finish);
xact_temps, *handler, finish, &(*i).second.components);
values.clear();
}
@ -383,9 +401,18 @@ void subtotal_transactions::operator()(transaction_t& xact)
if (i == values.end()) {
value_t temp;
add_transaction_to(xact, temp);
values.insert(values_pair(acct->fullname(), acct_value_t(acct, 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_transaction_to(xact, (*i).second.value);
if (remember_components)
(*i).second.components.push_back(&xact);
}
// If the account for this transaction is all virtual, mark it as
@ -478,8 +505,9 @@ void by_payee_transactions::operator()(transaction_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_transactions(handler));
payee_subtotals_pair
temp(xact.entry->payee,
new subtotal_transactions(handler, remember_components));
std::pair<payee_subtotals_map::iterator, bool> result
= payee_subtotals.insert(temp);

99
walk.h
View file

@ -94,8 +94,43 @@ struct transaction_xdata_t
account_t * account;
void * ptr;
transactions_list * component_xacts;
transaction_xdata_t()
: index(0), dflags(0), date(0), account(0), ptr(0) {}
: index(0), dflags(0), date(0), account(NULL), ptr(NULL),
component_xacts(NULL) {
DEBUG_PRINT("ledger.memory.ctors", "ctor transaction_xdata_t " << this);
}
~transaction_xdata_t() {
DEBUG_PRINT("ledger.memory.dtors", "dtor transaction_xdata_t " << this);
if (component_xacts)
delete component_xacts;
}
void remember_xact(transaction_t& xact) {
if (! component_xacts)
component_xacts = new transactions_list;
component_xacts->push_back(&xact);
}
bool have_component_xacts() const {
return component_xacts != NULL && ! component_xacts->empty();
}
void copy_component_xacts(transactions_list& xacts) {
for (transactions_list::const_iterator i = xacts.begin();
i != xacts.end();
i++)
remember_xact(**i);
}
void walk_component_xacts(item_handler<transaction_t>& handler) const {
for (transactions_list::const_iterator i = component_xacts->begin();
i != component_xacts->end();
i++)
handler(**i);
}
};
inline bool transaction_has_xdata(const transaction_t& xact) {
@ -323,6 +358,22 @@ class collapse_transactions : public item_handler<transaction_t>
virtual void operator()(transaction_t& xact);
};
class component_transactions : public item_handler<transaction_t>
{
item_predicate<transaction_t> pred;
public:
component_transactions(item_handler<transaction_t> * handler,
const value_expr_t * predicate)
: item_handler<transaction_t>(handler), pred(predicate) {}
component_transactions(item_handler<transaction_t> * handler,
const std::string& predicate)
: item_handler<transaction_t>(handler), pred(predicate) {}
virtual void operator()(transaction_t& xact);
};
class related_transactions : public item_handler<transaction_t>
{
transactions_list transactions;
@ -379,8 +430,10 @@ class changed_value_transactions : public item_handler<transaction_t>
class subtotal_transactions : public item_handler<transaction_t>
{
struct acct_value_t {
account_t * account;
value_t value;
account_t * account;
value_t value;
transactions_list components;
acct_value_t(account_t * a) : account(a) {}
acct_value_t(account_t * a, value_t& v) : account(a), value(v) {}
@ -393,6 +446,7 @@ class subtotal_transactions : public item_handler<transaction_t>
protected:
values_map values;
bool remember_components;
std::list<entry_t> entry_temps;
std::list<transaction_t> xact_temps;
@ -401,15 +455,16 @@ class subtotal_transactions : public item_handler<transaction_t>
std::time_t start;
std::time_t finish;
subtotal_transactions(item_handler<transaction_t> * handler)
: item_handler<transaction_t>(handler), start(0), finish(0) {}
subtotal_transactions(item_handler<transaction_t> * handler,
bool _remember_components = false)
: item_handler<transaction_t>(handler),
remember_components(_remember_components), start(0), finish(0) {}
#ifdef DEBUG_ENABLED
subtotal_transactions(const subtotal_transactions&) {
assert(0);
}
#endif
~subtotal_transactions() {
virtual ~subtotal_transactions() {
clear_entries_transactions(entry_temps);
}
@ -442,9 +497,11 @@ class interval_transactions : public subtotal_transactions
public:
interval_transactions(item_handler<transaction_t> * _handler,
const interval_t& _interval,
const value_expr_t * sort_order = NULL)
: subtotal_transactions(_handler), interval(_interval),
last_xact(NULL), started(false), sorter(NULL) {
const value_expr_t * sort_order = NULL,
bool remember_components = false)
: subtotal_transactions(_handler, remember_components),
interval(_interval), last_xact(NULL), started(false),
sorter(NULL) {
if (sort_order) {
sorter = new sort_transactions(handler, sort_order);
handler = sorter;
@ -452,15 +509,16 @@ class interval_transactions : public subtotal_transactions
}
interval_transactions(item_handler<transaction_t> * _handler,
const std::string& _interval,
const std::string& sort_order = "")
: subtotal_transactions(_handler), interval(_interval),
last_xact(NULL), started(false), sorter(NULL) {
const std::string& sort_order = "",
bool remember_components = false)
: subtotal_transactions(_handler, remember_components),
interval(_interval), last_xact(NULL), started(false),
sorter(NULL) {
if (! sort_order.empty()) {
sorter = new sort_transactions(handler, sort_order);
handler = sorter;
}
}
virtual ~interval_transactions() {
if (sorter)
delete sorter;
@ -482,11 +540,13 @@ class by_payee_transactions : public item_handler<transaction_t>
typedef std::pair<std::string, subtotal_transactions *> payee_subtotals_pair;
payee_subtotals_map payee_subtotals;
bool remember_components;
public:
by_payee_transactions(item_handler<transaction_t> * handler)
: item_handler<transaction_t>(handler) {}
by_payee_transactions(item_handler<transaction_t> * handler,
bool _remember_components = false)
: item_handler<transaction_t>(handler),
remember_components(_remember_components) {}
virtual ~by_payee_transactions();
virtual void flush();
@ -514,8 +574,9 @@ class dow_transactions : public subtotal_transactions
transactions_list days_of_the_week[7];
public:
dow_transactions(item_handler<transaction_t> * handler)
: subtotal_transactions(handler) {}
dow_transactions(item_handler<transaction_t> * handler,
bool remember_components = false)
: subtotal_transactions(handler, remember_components) {}
virtual void flush();
virtual void operator()(transaction_t& xact) {