fix to textual parsing, and a bit of reconstruction in main.cc
This commit is contained in:
parent
41604e0ea6
commit
f62a4906d1
10 changed files with 285 additions and 257 deletions
76
amount.cc
76
amount.cc
|
|
@ -1,4 +1,5 @@
|
|||
#include "ledger.h"
|
||||
#include "error.h"
|
||||
#include "util.h"
|
||||
|
||||
#include "gmp.h"
|
||||
|
|
@ -7,8 +8,6 @@
|
|||
|
||||
#define MPZ(x) ((MP_INT *)(x))
|
||||
|
||||
#define INIT() if (! quantity) _init()
|
||||
|
||||
namespace ledger {
|
||||
|
||||
static mpz_t full_divisor;
|
||||
|
|
@ -229,8 +228,14 @@ amount_t& amount_t::operator=(const double value)
|
|||
amount_t& amount_t::operator+=(const amount_t& amt)
|
||||
{
|
||||
if (amt.quantity) {
|
||||
assert(! commodity || commodity == amt.commodity);
|
||||
INIT();
|
||||
if (! quantity) {
|
||||
_init();
|
||||
commodity = amt.commodity;
|
||||
}
|
||||
|
||||
if (commodity != amt.commodity)
|
||||
throw amount_error("Adding amounts with different commodities");
|
||||
|
||||
mpz_add(MPZ(quantity), MPZ(quantity), MPZ(amt.quantity));
|
||||
}
|
||||
return *this;
|
||||
|
|
@ -239,8 +244,14 @@ amount_t& amount_t::operator+=(const amount_t& amt)
|
|||
amount_t& amount_t::operator-=(const amount_t& amt)
|
||||
{
|
||||
if (amt.quantity) {
|
||||
assert(commodity == amt.commodity);
|
||||
INIT();
|
||||
if (! quantity) {
|
||||
_init();
|
||||
commodity = amt.commodity;
|
||||
}
|
||||
|
||||
if (commodity != amt.commodity)
|
||||
throw amount_error("Subtracting amounts with different commodities");
|
||||
|
||||
mpz_sub(MPZ(quantity), MPZ(quantity), MPZ(amt.quantity));
|
||||
}
|
||||
return *this;
|
||||
|
|
@ -372,7 +383,10 @@ bool amount_t::operator<(const amount_t& amt) const
|
|||
return amt > 0;
|
||||
if (! amt.quantity) // equivalent to zero
|
||||
return *this < 0;
|
||||
assert(commodity == amt.commodity);
|
||||
|
||||
if (commodity != amt.commodity)
|
||||
throw amount_error("Comparing amounts with different commodities");
|
||||
|
||||
return mpz_cmp(MPZ(quantity), MPZ(amt.quantity)) < 0;
|
||||
}
|
||||
|
||||
|
|
@ -382,7 +396,10 @@ bool amount_t::operator<=(const amount_t& amt) const
|
|||
return amt >= 0;
|
||||
if (! amt.quantity) // equivalent to zero
|
||||
return *this <= 0;
|
||||
assert(commodity == amt.commodity);
|
||||
|
||||
if (commodity != amt.commodity)
|
||||
throw amount_error("Comparing amounts with different commodities");
|
||||
|
||||
return mpz_cmp(MPZ(quantity), MPZ(amt.quantity)) <= 0;
|
||||
}
|
||||
|
||||
|
|
@ -392,7 +409,10 @@ bool amount_t::operator>(const amount_t& amt) const
|
|||
return amt < 0;
|
||||
if (! amt.quantity) // equivalent to zero
|
||||
return *this > 0;
|
||||
assert(commodity == amt.commodity);
|
||||
|
||||
if (commodity != amt.commodity)
|
||||
throw amount_error("Comparing amounts with different commodities");
|
||||
|
||||
return mpz_cmp(MPZ(quantity), MPZ(amt.quantity)) > 0;
|
||||
}
|
||||
|
||||
|
|
@ -402,16 +422,23 @@ bool amount_t::operator>=(const amount_t& amt) const
|
|||
return amt <= 0;
|
||||
if (! amt.quantity) // equivalent to zero
|
||||
return *this >= 0;
|
||||
assert(commodity == amt.commodity);
|
||||
|
||||
if (commodity != amt.commodity)
|
||||
throw amount_error("Comparing amounts with different commodities");
|
||||
|
||||
return mpz_cmp(MPZ(quantity), MPZ(amt.quantity)) >= 0;
|
||||
}
|
||||
|
||||
bool amount_t::operator==(const amount_t& amt) const
|
||||
{
|
||||
if (commodity != amt.commodity)
|
||||
if (! quantity && ! amt.quantity)
|
||||
return true;
|
||||
else if (! quantity || ! amt.quantity)
|
||||
return false;
|
||||
assert(amt.quantity);
|
||||
assert(quantity);
|
||||
|
||||
if (commodity != amt.commodity)
|
||||
throw amount_error("Comparing amounts with different commodities");
|
||||
|
||||
return mpz_cmp(MPZ(quantity), MPZ(amt.quantity)) == 0;
|
||||
}
|
||||
|
||||
|
|
@ -448,7 +475,10 @@ amount_t& amount_t::operator*=(const amount_t& amt)
|
|||
if (! amt.quantity)
|
||||
return *this;
|
||||
|
||||
INIT();
|
||||
if (! quantity) {
|
||||
_init();
|
||||
commodity = amt.commodity;
|
||||
}
|
||||
|
||||
mpz_mul(MPZ(quantity), MPZ(quantity), MPZ(amt.quantity));
|
||||
mpz_tdiv_q(MPZ(quantity), MPZ(quantity), full_divisor);
|
||||
|
|
@ -461,7 +491,10 @@ amount_t& amount_t::operator/=(const amount_t& amt)
|
|||
if (! amt.quantity)
|
||||
return *this;
|
||||
|
||||
INIT();
|
||||
if (! quantity) {
|
||||
_init();
|
||||
commodity = amt.commodity;
|
||||
}
|
||||
|
||||
mpz_mul(MPZ(quantity), MPZ(quantity), full_divisor);
|
||||
mpz_tdiv_q(MPZ(quantity), MPZ(quantity), MPZ(amt.quantity));
|
||||
|
|
@ -474,7 +507,10 @@ amount_t& amount_t::operator%=(const amount_t& amt)
|
|||
if (! amt.quantity)
|
||||
return *this;
|
||||
|
||||
INIT();
|
||||
if (! quantity) {
|
||||
_init();
|
||||
commodity = amt.commodity;
|
||||
}
|
||||
|
||||
mpz_mul(MPZ(quantity), MPZ(quantity), full_divisor);
|
||||
mpz_tdiv_r(MPZ(quantity), MPZ(quantity), MPZ(amt.quantity));
|
||||
|
|
@ -650,7 +686,7 @@ void parse_commodity(std::istream& in, std::string& symbol)
|
|||
if (c == '"')
|
||||
in.get(c);
|
||||
else
|
||||
assert(0);
|
||||
throw amount_error("Quoted commodity symbol lacks closing quote");
|
||||
} else {
|
||||
READ_INTO(in, buf, 256, c, ! std::isspace(c) && ! std::isdigit(c) &&
|
||||
c != '-' && c != '.');
|
||||
|
|
@ -670,7 +706,8 @@ void amount_t::parse(std::istream& in)
|
|||
unsigned int flags = COMMODITY_STYLE_DEFAULTS;;
|
||||
unsigned int precision = MAX_PRECISION;
|
||||
|
||||
INIT();
|
||||
if (! quantity)
|
||||
_init();
|
||||
|
||||
char c = peek_next_nonws(in);
|
||||
if (std::isdigit(c) || c == '.' || c == '-') {
|
||||
|
|
@ -794,7 +831,8 @@ void amount_t::read_quantity(std::istream& in)
|
|||
in.read((char *)&len, sizeof(len));
|
||||
if (len) {
|
||||
in.read(buf, len);
|
||||
INIT();
|
||||
if (! quantity)
|
||||
_init();
|
||||
#ifdef WRITE_AMOUNTS_TEXTUALLY
|
||||
buf[len] = '\0';
|
||||
mpz_set_str(MPZ(quantity), buf, 10);
|
||||
|
|
|
|||
|
|
@ -97,7 +97,8 @@ Commodity reporting:\n\
|
|||
-A, --average report average transaction amount\n\
|
||||
-D, --deviation report deviation from the average\n\
|
||||
-X, --trend report average deviation from the average\n\
|
||||
-Z, --weighted-trend same as trend, but older values less significant\n\n\
|
||||
-Z, --weighted-trend same as trend, but older values are less significant\n\
|
||||
(-D, -X and -Z make little sense in balance reports)\n\n\
|
||||
Commands:\n\
|
||||
balance [REGEXP]... show balance totals for matching accounts\n\
|
||||
register [REGEXP]... show register of matching transactions\n\
|
||||
|
|
@ -345,7 +346,7 @@ OPT_BEGIN(trend, "X") {
|
|||
OPT_BEGIN(weighted_trend, "Z") {
|
||||
config->value_expr = "a";
|
||||
config->total_expr
|
||||
= "MD(MO/(1+(((t-d)/(30*86400))<0?0:((t-d)/(30*86400)))))";
|
||||
= "MD(MO/(1+(((N-d)/(30*86400))<0?0:((N-d)/(30*86400)))))";
|
||||
} OPT_END(weighted_trend);
|
||||
|
||||
} // namespace ledger
|
||||
|
|
|
|||
24
error.h
24
error.h
|
|
@ -8,8 +8,7 @@
|
|||
|
||||
namespace ledger {
|
||||
|
||||
class error : public std::exception
|
||||
{
|
||||
class error : public std::exception {
|
||||
std::string reason;
|
||||
public:
|
||||
error(const std::string& _reason) throw() : reason(_reason) {}
|
||||
|
|
@ -20,36 +19,37 @@ class error : public std::exception
|
|||
}
|
||||
};
|
||||
|
||||
class compute_error : public error
|
||||
{
|
||||
class amount_error : public error {
|
||||
public:
|
||||
amount_error(const std::string& reason) throw() : error(reason) {}
|
||||
virtual ~amount_error() throw() {}
|
||||
};
|
||||
|
||||
class compute_error : public error {
|
||||
public:
|
||||
compute_error(const std::string& reason) throw() : error(reason) {}
|
||||
virtual ~compute_error() throw() {}
|
||||
};
|
||||
|
||||
class value_expr_error : public error
|
||||
{
|
||||
class value_expr_error : public error {
|
||||
public:
|
||||
value_expr_error(const std::string& reason) throw() : error(reason) {}
|
||||
virtual ~value_expr_error() throw() {}
|
||||
};
|
||||
|
||||
class interval_expr_error : public error
|
||||
{
|
||||
class interval_expr_error : public error {
|
||||
public:
|
||||
interval_expr_error(const std::string& reason) throw() : error(reason) {}
|
||||
virtual ~interval_expr_error() throw() {}
|
||||
};
|
||||
|
||||
class format_error : public error
|
||||
{
|
||||
class format_error : public error {
|
||||
public:
|
||||
format_error(const std::string& reason) throw() : error(reason) {}
|
||||
virtual ~format_error() throw() {}
|
||||
};
|
||||
|
||||
class parse_error : public error
|
||||
{
|
||||
class parse_error : public error {
|
||||
unsigned int line;
|
||||
std::string file;
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -52,7 +52,11 @@ element_t * format_t::parse_elements(const std::string& fmt)
|
|||
char * q = buf;
|
||||
|
||||
for (const char * p = fmt.c_str(); *p; p++) {
|
||||
if (*p == '%') {
|
||||
if (*p != '%') {
|
||||
*q++ = *p;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (! result) {
|
||||
current = result = new element_t;
|
||||
} else {
|
||||
|
|
@ -141,9 +145,6 @@ element_t * format_t::parse_elements(const std::string& fmt)
|
|||
case 'T': current->type = element_t::TOTAL; break;
|
||||
case '_': current->type = element_t::SPACER; break;
|
||||
}
|
||||
} else {
|
||||
*q++ = *p;
|
||||
}
|
||||
}
|
||||
|
||||
if (q != buf) {
|
||||
|
|
|
|||
12
format.h
12
format.h
|
|
@ -113,10 +113,6 @@ class format_transactions : public item_handler<transaction_t>
|
|||
first_line_format(_first_line_format),
|
||||
next_lines_format(_next_lines_format), last_entry(NULL) {}
|
||||
|
||||
virtual ~format_transactions() {
|
||||
flush();
|
||||
}
|
||||
|
||||
virtual void flush() {
|
||||
output_stream.flush();
|
||||
}
|
||||
|
|
@ -148,10 +144,6 @@ class format_account : public item_handler<account_t>
|
|||
: output_stream(_output_stream), format(_format),
|
||||
disp_pred(display_predicate) {}
|
||||
|
||||
virtual ~format_account() {
|
||||
flush();
|
||||
}
|
||||
|
||||
static bool disp_subaccounts_p(const account_t * account,
|
||||
const item_predicate<account_t>& disp_pred,
|
||||
const account_t *& to_show);
|
||||
|
|
@ -201,10 +193,6 @@ class format_equity : public item_handler<account_t>
|
|||
first_line_format.format_elements(output_stream, details_t(&header_entry));
|
||||
}
|
||||
|
||||
virtual ~format_equity() {
|
||||
flush();
|
||||
}
|
||||
|
||||
virtual void flush() {
|
||||
account_t summary(NULL, "Equity:Opening Balances");
|
||||
summary.value = - total;
|
||||
|
|
|
|||
153
main.cc
153
main.cc
|
|
@ -106,8 +106,10 @@ regexps_to_predicate(std::list<std::string>::const_iterator begin,
|
|||
if (i != regexps.begin()) {
|
||||
config->predicate += "!";
|
||||
}
|
||||
else if (add_account_short_masks &&
|
||||
(*i).find(':') == std::string::npos) {
|
||||
else if (add_account_short_masks) {
|
||||
if ((*i).find(':') != std::string::npos) {
|
||||
config->show_subtotal = true;
|
||||
} else {
|
||||
if (! config->display_predicate.empty())
|
||||
config->display_predicate += "&";
|
||||
else if (! config->show_empty)
|
||||
|
|
@ -117,6 +119,7 @@ regexps_to_predicate(std::list<std::string>::const_iterator begin,
|
|||
config->display_predicate += *i;
|
||||
config->display_predicate += ")/";
|
||||
}
|
||||
}
|
||||
|
||||
if (! account_regexp)
|
||||
config->predicate += "/";
|
||||
|
|
@ -257,7 +260,28 @@ int main(int argc, char * argv[], char * envp[])
|
|||
return 1;
|
||||
}
|
||||
|
||||
// Process the remaining command-line arguments
|
||||
// Configure some other options depending on report type
|
||||
|
||||
bool show_all_related = false;
|
||||
|
||||
if (command == "p" || command == "e") {
|
||||
config->show_related =
|
||||
show_all_related =
|
||||
config->show_subtotal = true;
|
||||
}
|
||||
else if (command == "E") {
|
||||
config->show_subtotal = true;
|
||||
}
|
||||
else if (config->show_related) {
|
||||
if (command == "r") {
|
||||
config->show_inverted = true;
|
||||
} else {
|
||||
config->show_subtotal = true;
|
||||
show_all_related = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Process remaining command-line arguments
|
||||
|
||||
std::auto_ptr<entry_t> new_entry;
|
||||
if (command == "e") {
|
||||
|
|
@ -278,7 +302,7 @@ int main(int argc, char * argv[], char * envp[])
|
|||
regexps_to_predicate(i, args.end(), config);
|
||||
}
|
||||
|
||||
// Compile the predicates
|
||||
// Setup default value for the display predicate
|
||||
|
||||
if (config->display_predicate.empty()) {
|
||||
if (command == "b") {
|
||||
|
|
@ -295,7 +319,7 @@ int main(int argc, char * argv[], char * envp[])
|
|||
}
|
||||
}
|
||||
|
||||
// Compile the sorting criteria
|
||||
// Compile sorting criteria
|
||||
|
||||
std::auto_ptr<value_expr_t> sort_order;
|
||||
|
||||
|
|
@ -319,7 +343,7 @@ int main(int argc, char * argv[], char * envp[])
|
|||
}
|
||||
}
|
||||
|
||||
// Setup the meaning of %t and %T, used in format strings
|
||||
// Setup the values of %t and %T, used in format strings
|
||||
|
||||
try {
|
||||
#ifdef NO_CLEANUP
|
||||
|
|
@ -347,27 +371,7 @@ int main(int argc, char * argv[], char * envp[])
|
|||
return 1;
|
||||
}
|
||||
|
||||
// Configure some option depending on the report type
|
||||
|
||||
bool show_all_related = false;
|
||||
|
||||
if (command == "p" || command == "e") {
|
||||
config->show_related =
|
||||
show_all_related =
|
||||
config->show_subtotal = true;
|
||||
}
|
||||
else if (command == "E") {
|
||||
config->show_subtotal = true;
|
||||
}
|
||||
else if (config->show_related) {
|
||||
if (command == "r")
|
||||
config->show_inverted = true;
|
||||
else
|
||||
show_all_related = true;
|
||||
}
|
||||
|
||||
// Setup a few local and global variables, depending on the config
|
||||
// settings.
|
||||
// Setup local and global variables, depending on config settings.
|
||||
|
||||
std::auto_ptr<std::ostream> output_stream;
|
||||
std::auto_ptr<interval_t> report_interval;
|
||||
|
|
@ -458,59 +462,23 @@ int main(int argc, char * argv[], char * envp[])
|
|||
|
||||
TIMER_START(report_gen);
|
||||
|
||||
if (command == "b") {
|
||||
std::auto_ptr<item_handler<transaction_t> > formatter;
|
||||
formatter.reset(new add_to_account_value);
|
||||
if (config->show_related)
|
||||
formatter.reset(new related_transactions(formatter.release(),
|
||||
show_all_related));
|
||||
formatter.reset(new filter_transactions(formatter.release(),
|
||||
config->predicate));
|
||||
walk_entries(journal->entries, *formatter);
|
||||
formatter->flush();
|
||||
|
||||
format_account acct_formatter(OUT(), format, config->display_predicate);
|
||||
sum_accounts(journal->master);
|
||||
walk_accounts(journal->master, acct_formatter, sort_order.get());
|
||||
acct_formatter.flush();
|
||||
|
||||
journal->master->value = journal->master->total;
|
||||
if (format_account::display_account(journal->master,
|
||||
item_predicate<account_t>("T"),
|
||||
true)) {
|
||||
std::string end_format = "--------------------\n";
|
||||
format.reset(end_format + f);
|
||||
format.format_elements(OUT(), details_t(journal->master));
|
||||
}
|
||||
}
|
||||
else if (command == "E") {
|
||||
std::auto_ptr<item_handler<transaction_t> > formatter;
|
||||
formatter.reset(new add_to_account_value);
|
||||
formatter.reset(new filter_transactions(formatter.release(),
|
||||
config->predicate));
|
||||
walk_entries(journal->entries, *formatter);
|
||||
formatter->flush();
|
||||
|
||||
format_equity acct_formatter(OUT(), format, nformat,
|
||||
config->display_predicate);
|
||||
sum_accounts(journal->master);
|
||||
walk_accounts(journal->master, acct_formatter, sort_order.get());
|
||||
acct_formatter.flush();
|
||||
}
|
||||
else if (command == "e") {
|
||||
format_transactions formatter(OUT(), format, nformat);
|
||||
walk_transactions(new_entry->transactions, formatter);
|
||||
formatter.flush();
|
||||
}
|
||||
else {
|
||||
std::auto_ptr<item_handler<transaction_t> > formatter;
|
||||
|
||||
// Stack up all the formatter needed to fulfills the user's
|
||||
// requests. Some of these are order dependent, in terms of
|
||||
// whether calc_transactions occurs before or after them.
|
||||
|
||||
std::auto_ptr<item_handler<transaction_t> > formatter;
|
||||
|
||||
// format_transactions write each transaction received to the
|
||||
// output stream.
|
||||
if (command == "b" || command == "E") {
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (DEBUG("ledger.balance.items")) {
|
||||
formatter.reset(new format_transactions(OUT(), format, nformat));
|
||||
formatter.reset(new set_account_value(formatter.release()));
|
||||
} else
|
||||
#endif
|
||||
formatter.reset(new set_account_value);
|
||||
} else {
|
||||
formatter.reset(new format_transactions(OUT(), format, nformat));
|
||||
|
||||
// sort_transactions will sort all the transactions it sees, based
|
||||
|
|
@ -562,6 +530,7 @@ int main(int argc, char * argv[], char * envp[])
|
|||
interval_begin));
|
||||
else if (config->days_of_the_week)
|
||||
formatter.reset(new dow_transactions(formatter.release()));
|
||||
}
|
||||
|
||||
// related_transactions will pass along all transactions related
|
||||
// to the transaction received. If `show_all_related' is true,
|
||||
|
|
@ -579,10 +548,43 @@ int main(int argc, char * argv[], char * envp[])
|
|||
|
||||
// Once the filters are chained, walk `journal's entries and start
|
||||
// feeding each transaction that matches `predicate' to the chain.
|
||||
if (command == "e")
|
||||
walk_transactions(new_entry->transactions, *formatter);
|
||||
else
|
||||
walk_entries(journal->entries, *formatter);
|
||||
|
||||
formatter->flush();
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
// At this point all printing is finished if doing a register
|
||||
// report; but if it's a balance or equity report, we've only
|
||||
// finished calculating the totals and there is still reporting to
|
||||
// be done.
|
||||
|
||||
if (command == "b") {
|
||||
format_account acct_formatter(OUT(), format, config->display_predicate);
|
||||
sum_accounts(journal->master);
|
||||
walk_accounts(journal->master, acct_formatter, sort_order.get());
|
||||
acct_formatter.flush();
|
||||
|
||||
journal->master->value = journal->master->total;
|
||||
|
||||
if (format_account::display_account(journal->master,
|
||||
item_predicate<account_t>("T"),
|
||||
true)) {
|
||||
std::string end_format = "--------------------\n";
|
||||
format.reset(end_format + f);
|
||||
format.format_elements(OUT(), details_t(journal->master));
|
||||
}
|
||||
}
|
||||
else if (command == "E") {
|
||||
format_equity acct_formatter(OUT(), format, nformat,
|
||||
config->display_predicate);
|
||||
sum_accounts(journal->master);
|
||||
walk_accounts(journal->master, acct_formatter, sort_order.get());
|
||||
acct_formatter.flush();
|
||||
}
|
||||
|
||||
#ifndef NO_CLEANUP
|
||||
// The transaction display flags (dflags) are not recorded in the
|
||||
// binary cache, and only need to be cleared if the transactions
|
||||
// are to be displayed a second time.
|
||||
|
|
@ -590,7 +592,6 @@ int main(int argc, char * argv[], char * envp[])
|
|||
walk_entries(journal->entries, cleanup);
|
||||
cleanup.flush();
|
||||
#endif
|
||||
}
|
||||
|
||||
TIMER_STOP(report_gen);
|
||||
|
||||
|
|
|
|||
|
|
@ -9,3 +9,4 @@
|
|||
2004/05/29 Restaurant
|
||||
Expenses:Food $50.00
|
||||
Liabilities:MasterCard
|
||||
|
||||
|
|
|
|||
|
|
@ -110,6 +110,10 @@ transaction_t * parse_transaction(std::istream& in, account_t * account,
|
|||
in.getline(line, MAX_LINE);
|
||||
linenum++;
|
||||
|
||||
// Skip a possible blank line
|
||||
if (*skip_ws(line) == '\0')
|
||||
return NULL;
|
||||
|
||||
return parse_transaction_text(line, account, entry);
|
||||
}
|
||||
|
||||
|
|
@ -321,8 +325,7 @@ unsigned int parse_textual_journal(std::istream& in, journal_t * journal,
|
|||
if (peek_next_nonws(in) != '\n') {
|
||||
in.getline(line, MAX_LINE);
|
||||
linenum++;
|
||||
throw parse_error(path, linenum,
|
||||
"Ignoring entry beginning with whitespace");
|
||||
throw parse_error(path, linenum, "Line begins with whitespace");
|
||||
}
|
||||
// fall through...
|
||||
|
||||
|
|
|
|||
4
walk.cc
4
walk.cc
|
|
@ -59,8 +59,8 @@ void collapse_transactions::report_cumulative_subtotal()
|
|||
for (amounts_map::const_iterator i = result.amounts.begin();
|
||||
i != result.amounts.end();
|
||||
i++) {
|
||||
transaction_t * total_xact = new transaction_t(last_entry,
|
||||
totals_account);
|
||||
transaction_t * total_xact
|
||||
= new transaction_t(last_entry, totals_account);
|
||||
xact_temps.push_back(total_xact);
|
||||
|
||||
total_xact->amount = (*i).second;
|
||||
|
|
|
|||
33
walk.h
33
walk.h
|
|
@ -18,18 +18,19 @@ struct item_handler {
|
|||
public:
|
||||
item_handler() : handler(NULL) {}
|
||||
item_handler(item_handler * _handler) : handler(_handler) {}
|
||||
virtual ~item_handler() {}
|
||||
virtual void close() {
|
||||
if (handler) {
|
||||
|
||||
virtual ~item_handler() {
|
||||
if (handler)
|
||||
delete handler;
|
||||
handler = NULL;
|
||||
}
|
||||
}
|
||||
virtual void flush() {
|
||||
if (handler)
|
||||
handler->flush();
|
||||
}
|
||||
virtual void operator()(T * item) = 0;
|
||||
virtual void operator()(T * item) {
|
||||
if (handler)
|
||||
(*handler)(item);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
|
|
@ -112,12 +113,18 @@ class clear_display_flags : public item_handler<transaction_t>
|
|||
}
|
||||
};
|
||||
|
||||
class add_to_account_value : public item_handler<transaction_t>
|
||||
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) {
|
||||
xact->account->value += *xact;
|
||||
xact->account->count++;
|
||||
|
||||
if (handler)
|
||||
(*handler)(xact);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -131,7 +138,6 @@ class sort_transactions : public item_handler<transaction_t>
|
|||
const value_expr_t * _sort_order)
|
||||
: item_handler<transaction_t>(handler),
|
||||
sort_order(_sort_order) {}
|
||||
virtual ~sort_transactions() { close(); }
|
||||
|
||||
virtual void flush();
|
||||
virtual void operator()(transaction_t * xact) {
|
||||
|
|
@ -148,8 +154,6 @@ class filter_transactions : public item_handler<transaction_t>
|
|||
const std::string& predicate)
|
||||
: item_handler<transaction_t>(handler), pred(predicate) {}
|
||||
|
||||
virtual ~filter_transactions() { close(); }
|
||||
|
||||
virtual void operator()(transaction_t * xact) {
|
||||
if (pred(xact))
|
||||
(*handler)(xact);
|
||||
|
|
@ -167,8 +171,6 @@ class calc_transactions : public item_handler<transaction_t>
|
|||
: item_handler<transaction_t>(handler),
|
||||
last_xact(NULL), inverted(_inverted) {}
|
||||
|
||||
virtual ~calc_transactions() { close(); }
|
||||
|
||||
virtual void operator()(transaction_t * xact);
|
||||
};
|
||||
|
||||
|
|
@ -189,7 +191,6 @@ class collapse_transactions : public item_handler<transaction_t>
|
|||
}
|
||||
|
||||
virtual ~collapse_transactions() {
|
||||
close();
|
||||
delete totals_account;
|
||||
for (transactions_deque::iterator i = xact_temps.begin();
|
||||
i != xact_temps.end();
|
||||
|
|
@ -237,8 +238,6 @@ class changed_value_transactions : public item_handler<transaction_t>
|
|||
changed_values_only(_changed_values_only), last_xact(NULL) {}
|
||||
|
||||
virtual ~changed_value_transactions() {
|
||||
close();
|
||||
|
||||
for (entries_deque::iterator i = entry_temps.begin();
|
||||
i != entry_temps.end();
|
||||
i++)
|
||||
|
|
@ -275,8 +274,6 @@ class subtotal_transactions : public item_handler<transaction_t>
|
|||
: item_handler<transaction_t>(handler) {}
|
||||
|
||||
virtual ~subtotal_transactions() {
|
||||
close();
|
||||
|
||||
for (entries_deque::iterator i = entry_temps.begin();
|
||||
i != entry_temps.end();
|
||||
i++)
|
||||
|
|
@ -342,8 +339,6 @@ class related_transactions : public item_handler<transaction_t>
|
|||
: item_handler<transaction_t>(handler),
|
||||
also_matching(_also_matching) {}
|
||||
|
||||
virtual ~related_transactions() { close(); }
|
||||
|
||||
virtual void operator()(transaction_t * xact) {
|
||||
for (transactions_list::iterator i = xact->entry->transactions.begin();
|
||||
i != xact->entry->transactions.end();
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue