summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--amount.cc76
-rw-r--r--config.cc5
-rw-r--r--error.h24
-rw-r--r--format.cc155
-rw-r--r--format.h12
-rw-r--r--main.cc223
-rw-r--r--sample.dat1
-rw-r--r--textual.cc7
-rw-r--r--walk.cc6
-rw-r--r--walk.h33
10 files changed, 285 insertions, 257 deletions
diff --git a/amount.cc b/amount.cc
index 1ba5da7f..d8e5a85d 100644
--- a/amount.cc
+++ b/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);
diff --git a/config.cc b/config.cc
index ecf3d649..56b56761 100644
--- a/config.cc
+++ b/config.cc
@@ -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
diff --git a/error.h b/error.h
index 5373f473..a0c25336 100644
--- a/error.h
+++ b/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:
diff --git a/format.cc b/format.cc
index 42d5a082..7b17a4cd 100644
--- a/format.cc
+++ b/format.cc
@@ -52,97 +52,98 @@ 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 (! result) {
- current = result = new element_t;
- } else {
- current->next = new element_t;
- current = current->next;
- }
+ if (*p != '%') {
+ *q++ = *p;
+ continue;
+ }
- if (q != buf) {
- current->type = element_t::STRING;
- current->chars = std::string(buf, q);
- q = buf;
+ if (! result) {
+ current = result = new element_t;
+ } else {
+ current->next = new element_t;
+ current = current->next;
+ }
- current->next = new element_t;
- current = current->next;
- }
+ if (q != buf) {
+ current->type = element_t::STRING;
+ current->chars = std::string(buf, q);
+ q = buf;
+ current->next = new element_t;
+ current = current->next;
+ }
+
+ ++p;
+ if (*p == '-') {
+ current->align_left = true;
++p;
- if (*p == '-') {
- current->align_left = true;
- ++p;
- }
+ }
+
+ int num = 0;
+ while (*p && std::isdigit(*p)) {
+ num *= 10;
+ num += *p++ - '0';
+ }
+ current->min_width = num;
- int num = 0;
+ if (*p == '.') {
+ ++p;
+ num = 0;
while (*p && std::isdigit(*p)) {
num *= 10;
num += *p++ - '0';
}
- current->min_width = num;
-
- if (*p == '.') {
- ++p;
- num = 0;
- while (*p && std::isdigit(*p)) {
- num *= 10;
- num += *p++ - '0';
- }
- current->max_width = num;
- if (current->min_width == 0)
- current->min_width = current->max_width;
- }
-
- switch (*p) {
- case '%':
- current->type = element_t::STRING;
- current->chars = "%";
- break;
-
- case '(': {
- ++p;
- const char * b = p;
- while (*p && *p != ')')
- p++;
- if (*p != ')')
- throw format_error("Missing ')'");
+ current->max_width = num;
+ if (current->min_width == 0)
+ current->min_width = current->max_width;
+ }
- current->type = element_t::VALUE_EXPR;
- current->val_expr = parse_value_expr(std::string(b, p));
- break;
- }
+ switch (*p) {
+ case '%':
+ current->type = element_t::STRING;
+ current->chars = "%";
+ break;
- case '[': {
- ++p;
- const char * b = p;
- while (*p && *p != ']')
- p++;
- if (*p != ']')
- throw format_error("Missing ']'");
+ case '(': {
+ ++p;
+ const char * b = p;
+ while (*p && *p != ')')
+ p++;
+ if (*p != ')')
+ throw format_error("Missing ')'");
+
+ current->type = element_t::VALUE_EXPR;
+ current->val_expr = parse_value_expr(std::string(b, p));
+ break;
+ }
- current->type = element_t::DATE_STRING;
- current->chars = std::string(b, p);
- break;
- }
+ case '[': {
+ ++p;
+ const char * b = p;
+ while (*p && *p != ']')
+ p++;
+ if (*p != ']')
+ throw format_error("Missing ']'");
+
+ current->type = element_t::DATE_STRING;
+ current->chars = std::string(b, p);
+ break;
+ }
- case 'D':
- current->type = element_t::DATE_STRING;
- current->chars = format_t::date_format;
- break;
+ case 'D':
+ current->type = element_t::DATE_STRING;
+ current->chars = format_t::date_format;
+ break;
- case 'X': current->type = element_t::CLEARED; break;
- case 'C': current->type = element_t::CODE; break;
- case 'P': current->type = element_t::PAYEE; break;
- case 'n': current->type = element_t::ACCOUNT_NAME; break;
- case 'N': current->type = element_t::ACCOUNT_FULLNAME; break;
- case 'o': current->type = element_t::OPT_AMOUNT; break;
- case 't': current->type = element_t::VALUE; break;
- case 'T': current->type = element_t::TOTAL; break;
- case '_': current->type = element_t::SPACER; break;
- }
- } else {
- *q++ = *p;
+ case 'X': current->type = element_t::CLEARED; break;
+ case 'C': current->type = element_t::CODE; break;
+ case 'P': current->type = element_t::PAYEE; break;
+ case 'n': current->type = element_t::ACCOUNT_NAME; break;
+ case 'N': current->type = element_t::ACCOUNT_FULLNAME; break;
+ case 'o': current->type = element_t::OPT_AMOUNT; break;
+ case 't': current->type = element_t::VALUE; break;
+ case 'T': current->type = element_t::TOTAL; break;
+ case '_': current->type = element_t::SPACER; break;
}
}
diff --git a/format.h b/format.h
index ba488f68..dd578dbd 100644
--- a/format.h
+++ b/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;
diff --git a/main.cc b/main.cc
index ba18a2ff..d95ec16b 100644
--- a/main.cc
+++ b/main.cc
@@ -106,16 +106,19 @@ 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) {
- if (! config->display_predicate.empty())
- config->display_predicate += "&";
- else if (! config->show_empty)
- config->display_predicate += "T&";
-
- config->display_predicate += "///(?:";
- config->display_predicate += *i;
- config->display_predicate += ")/";
+ 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)
+ config->display_predicate += "T&";
+
+ config->display_predicate += "///(?:";
+ config->display_predicate += *i;
+ config->display_predicate += ")/";
+ }
}
if (! account_regexp)
@@ -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();
+ // 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.
- 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();
+ std::auto_ptr<item_handler<transaction_t> > formatter;
- 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.
-
- // format_transactions write each transaction received to the
- // output stream.
+ // 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,36 +530,69 @@ 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,
- // then all the entry's transactions are passed; meaning that if
- // one transaction of an entry is to be printed, all the
- // transaction for that entry will be printed.
- if (config->show_related)
- formatter.reset(new related_transactions(formatter.release(),
- show_all_related));
-
- // This filter_transactions will only pass through transactions
- // matching the `predicate'.
- formatter.reset(new filter_transactions(formatter.release(),
- config->predicate));
-
- // Once the filters are chained, walk `journal's entries and start
- // feeding each transaction that matches `predicate' to the chain.
+ // related_transactions will pass along all transactions related
+ // to the transaction received. If `show_all_related' is true,
+ // then all the entry's transactions are passed; meaning that if
+ // one transaction of an entry is to be printed, all the
+ // transaction for that entry will be printed.
+ if (config->show_related)
+ formatter.reset(new related_transactions(formatter.release(),
+ show_all_related));
+
+ // This filter_transactions will only pass through transactions
+ // matching the `predicate'.
+ formatter.reset(new filter_transactions(formatter.release(),
+ config->predicate));
+
+ // 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
- // 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.
- clear_display_flags cleanup;
- walk_entries(journal->entries, cleanup);
- cleanup.flush();
-#endif
+ formatter->flush();
+
+ // 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.
+ clear_display_flags cleanup;
+ walk_entries(journal->entries, cleanup);
+ cleanup.flush();
+#endif
+
TIMER_STOP(report_gen);
// Save the cache, if need be
diff --git a/sample.dat b/sample.dat
index 4e714275..335083d8 100644
--- a/sample.dat
+++ b/sample.dat
@@ -9,3 +9,4 @@
2004/05/29 Restaurant
Expenses:Food $50.00
Liabilities:MasterCard
+
diff --git a/textual.cc b/textual.cc
index df7d0242..564b2cd2 100644
--- a/textual.cc
+++ b/textual.cc
@@ -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...
diff --git a/walk.cc b/walk.cc
index c77647d6..908618b5 100644
--- a/walk.cc
+++ b/walk.cc
@@ -42,7 +42,7 @@ void calc_transactions::operator()(transaction_t * xact)
xact->cost.negate();
}
- last_xact = xact;
+ last_xact = xact;
}
void collapse_transactions::report_cumulative_subtotal()
@@ -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;
diff --git a/walk.h b/walk.h
index bced95d6..41b0d456 100644
--- a/walk.h
+++ b/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();