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 "ledger.h"
|
||||||
|
#include "error.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
#include "gmp.h"
|
#include "gmp.h"
|
||||||
|
|
@ -7,8 +8,6 @@
|
||||||
|
|
||||||
#define MPZ(x) ((MP_INT *)(x))
|
#define MPZ(x) ((MP_INT *)(x))
|
||||||
|
|
||||||
#define INIT() if (! quantity) _init()
|
|
||||||
|
|
||||||
namespace ledger {
|
namespace ledger {
|
||||||
|
|
||||||
static mpz_t full_divisor;
|
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)
|
amount_t& amount_t::operator+=(const amount_t& amt)
|
||||||
{
|
{
|
||||||
if (amt.quantity) {
|
if (amt.quantity) {
|
||||||
assert(! commodity || commodity == amt.commodity);
|
if (! quantity) {
|
||||||
INIT();
|
_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));
|
mpz_add(MPZ(quantity), MPZ(quantity), MPZ(amt.quantity));
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
|
|
@ -239,8 +244,14 @@ amount_t& amount_t::operator+=(const amount_t& amt)
|
||||||
amount_t& amount_t::operator-=(const amount_t& amt)
|
amount_t& amount_t::operator-=(const amount_t& amt)
|
||||||
{
|
{
|
||||||
if (amt.quantity) {
|
if (amt.quantity) {
|
||||||
assert(commodity == amt.commodity);
|
if (! quantity) {
|
||||||
INIT();
|
_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));
|
mpz_sub(MPZ(quantity), MPZ(quantity), MPZ(amt.quantity));
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
|
|
@ -372,7 +383,10 @@ bool amount_t::operator<(const amount_t& amt) const
|
||||||
return amt > 0;
|
return amt > 0;
|
||||||
if (! amt.quantity) // equivalent to zero
|
if (! amt.quantity) // equivalent to zero
|
||||||
return *this < 0;
|
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;
|
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;
|
return amt >= 0;
|
||||||
if (! amt.quantity) // equivalent to zero
|
if (! amt.quantity) // equivalent to zero
|
||||||
return *this <= 0;
|
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;
|
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;
|
return amt < 0;
|
||||||
if (! amt.quantity) // equivalent to zero
|
if (! amt.quantity) // equivalent to zero
|
||||||
return *this > 0;
|
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;
|
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;
|
return amt <= 0;
|
||||||
if (! amt.quantity) // equivalent to zero
|
if (! amt.quantity) // equivalent to zero
|
||||||
return *this >= 0;
|
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;
|
return mpz_cmp(MPZ(quantity), MPZ(amt.quantity)) >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool amount_t::operator==(const amount_t& amt) const
|
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;
|
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;
|
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)
|
if (! amt.quantity)
|
||||||
return *this;
|
return *this;
|
||||||
|
|
||||||
INIT();
|
if (! quantity) {
|
||||||
|
_init();
|
||||||
|
commodity = amt.commodity;
|
||||||
|
}
|
||||||
|
|
||||||
mpz_mul(MPZ(quantity), MPZ(quantity), MPZ(amt.quantity));
|
mpz_mul(MPZ(quantity), MPZ(quantity), MPZ(amt.quantity));
|
||||||
mpz_tdiv_q(MPZ(quantity), MPZ(quantity), full_divisor);
|
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)
|
if (! amt.quantity)
|
||||||
return *this;
|
return *this;
|
||||||
|
|
||||||
INIT();
|
if (! quantity) {
|
||||||
|
_init();
|
||||||
|
commodity = amt.commodity;
|
||||||
|
}
|
||||||
|
|
||||||
mpz_mul(MPZ(quantity), MPZ(quantity), full_divisor);
|
mpz_mul(MPZ(quantity), MPZ(quantity), full_divisor);
|
||||||
mpz_tdiv_q(MPZ(quantity), MPZ(quantity), MPZ(amt.quantity));
|
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)
|
if (! amt.quantity)
|
||||||
return *this;
|
return *this;
|
||||||
|
|
||||||
INIT();
|
if (! quantity) {
|
||||||
|
_init();
|
||||||
|
commodity = amt.commodity;
|
||||||
|
}
|
||||||
|
|
||||||
mpz_mul(MPZ(quantity), MPZ(quantity), full_divisor);
|
mpz_mul(MPZ(quantity), MPZ(quantity), full_divisor);
|
||||||
mpz_tdiv_r(MPZ(quantity), MPZ(quantity), MPZ(amt.quantity));
|
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 == '"')
|
if (c == '"')
|
||||||
in.get(c);
|
in.get(c);
|
||||||
else
|
else
|
||||||
assert(0);
|
throw amount_error("Quoted commodity symbol lacks closing quote");
|
||||||
} else {
|
} else {
|
||||||
READ_INTO(in, buf, 256, c, ! std::isspace(c) && ! std::isdigit(c) &&
|
READ_INTO(in, buf, 256, c, ! std::isspace(c) && ! std::isdigit(c) &&
|
||||||
c != '-' && c != '.');
|
c != '-' && c != '.');
|
||||||
|
|
@ -670,7 +706,8 @@ void amount_t::parse(std::istream& in)
|
||||||
unsigned int flags = COMMODITY_STYLE_DEFAULTS;;
|
unsigned int flags = COMMODITY_STYLE_DEFAULTS;;
|
||||||
unsigned int precision = MAX_PRECISION;
|
unsigned int precision = MAX_PRECISION;
|
||||||
|
|
||||||
INIT();
|
if (! quantity)
|
||||||
|
_init();
|
||||||
|
|
||||||
char c = peek_next_nonws(in);
|
char c = peek_next_nonws(in);
|
||||||
if (std::isdigit(c) || c == '.' || c == '-') {
|
if (std::isdigit(c) || c == '.' || c == '-') {
|
||||||
|
|
@ -794,7 +831,8 @@ void amount_t::read_quantity(std::istream& in)
|
||||||
in.read((char *)&len, sizeof(len));
|
in.read((char *)&len, sizeof(len));
|
||||||
if (len) {
|
if (len) {
|
||||||
in.read(buf, len);
|
in.read(buf, len);
|
||||||
INIT();
|
if (! quantity)
|
||||||
|
_init();
|
||||||
#ifdef WRITE_AMOUNTS_TEXTUALLY
|
#ifdef WRITE_AMOUNTS_TEXTUALLY
|
||||||
buf[len] = '\0';
|
buf[len] = '\0';
|
||||||
mpz_set_str(MPZ(quantity), buf, 10);
|
mpz_set_str(MPZ(quantity), buf, 10);
|
||||||
|
|
|
||||||
|
|
@ -97,7 +97,8 @@ Commodity reporting:\n\
|
||||||
-A, --average report average transaction amount\n\
|
-A, --average report average transaction amount\n\
|
||||||
-D, --deviation report deviation from the average\n\
|
-D, --deviation report deviation from the average\n\
|
||||||
-X, --trend report average 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\
|
Commands:\n\
|
||||||
balance [REGEXP]... show balance totals for matching accounts\n\
|
balance [REGEXP]... show balance totals for matching accounts\n\
|
||||||
register [REGEXP]... show register of matching transactions\n\
|
register [REGEXP]... show register of matching transactions\n\
|
||||||
|
|
@ -345,7 +346,7 @@ OPT_BEGIN(trend, "X") {
|
||||||
OPT_BEGIN(weighted_trend, "Z") {
|
OPT_BEGIN(weighted_trend, "Z") {
|
||||||
config->value_expr = "a";
|
config->value_expr = "a";
|
||||||
config->total_expr
|
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);
|
} OPT_END(weighted_trend);
|
||||||
|
|
||||||
} // namespace ledger
|
} // namespace ledger
|
||||||
|
|
|
||||||
24
error.h
24
error.h
|
|
@ -8,8 +8,7 @@
|
||||||
|
|
||||||
namespace ledger {
|
namespace ledger {
|
||||||
|
|
||||||
class error : public std::exception
|
class error : public std::exception {
|
||||||
{
|
|
||||||
std::string reason;
|
std::string reason;
|
||||||
public:
|
public:
|
||||||
error(const std::string& _reason) throw() : reason(_reason) {}
|
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:
|
public:
|
||||||
compute_error(const std::string& reason) throw() : error(reason) {}
|
compute_error(const std::string& reason) throw() : error(reason) {}
|
||||||
virtual ~compute_error() throw() {}
|
virtual ~compute_error() throw() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class value_expr_error : public error
|
class value_expr_error : public error {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
value_expr_error(const std::string& reason) throw() : error(reason) {}
|
value_expr_error(const std::string& reason) throw() : error(reason) {}
|
||||||
virtual ~value_expr_error() throw() {}
|
virtual ~value_expr_error() throw() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class interval_expr_error : public error
|
class interval_expr_error : public error {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
interval_expr_error(const std::string& reason) throw() : error(reason) {}
|
interval_expr_error(const std::string& reason) throw() : error(reason) {}
|
||||||
virtual ~interval_expr_error() throw() {}
|
virtual ~interval_expr_error() throw() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class format_error : public error
|
class format_error : public error {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
format_error(const std::string& reason) throw() : error(reason) {}
|
format_error(const std::string& reason) throw() : error(reason) {}
|
||||||
virtual ~format_error() throw() {}
|
virtual ~format_error() throw() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class parse_error : public error
|
class parse_error : public error {
|
||||||
{
|
|
||||||
unsigned int line;
|
unsigned int line;
|
||||||
std::string file;
|
std::string file;
|
||||||
public:
|
public:
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,11 @@ element_t * format_t::parse_elements(const std::string& fmt)
|
||||||
char * q = buf;
|
char * q = buf;
|
||||||
|
|
||||||
for (const char * p = fmt.c_str(); *p; p++) {
|
for (const char * p = fmt.c_str(); *p; p++) {
|
||||||
if (*p == '%') {
|
if (*p != '%') {
|
||||||
|
*q++ = *p;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (! result) {
|
if (! result) {
|
||||||
current = result = new element_t;
|
current = result = new element_t;
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -141,9 +145,6 @@ element_t * format_t::parse_elements(const std::string& fmt)
|
||||||
case 'T': current->type = element_t::TOTAL; break;
|
case 'T': current->type = element_t::TOTAL; break;
|
||||||
case '_': current->type = element_t::SPACER; break;
|
case '_': current->type = element_t::SPACER; break;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
*q++ = *p;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (q != buf) {
|
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),
|
first_line_format(_first_line_format),
|
||||||
next_lines_format(_next_lines_format), last_entry(NULL) {}
|
next_lines_format(_next_lines_format), last_entry(NULL) {}
|
||||||
|
|
||||||
virtual ~format_transactions() {
|
|
||||||
flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void flush() {
|
virtual void flush() {
|
||||||
output_stream.flush();
|
output_stream.flush();
|
||||||
}
|
}
|
||||||
|
|
@ -148,10 +144,6 @@ class format_account : public item_handler<account_t>
|
||||||
: output_stream(_output_stream), format(_format),
|
: output_stream(_output_stream), format(_format),
|
||||||
disp_pred(display_predicate) {}
|
disp_pred(display_predicate) {}
|
||||||
|
|
||||||
virtual ~format_account() {
|
|
||||||
flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool disp_subaccounts_p(const account_t * account,
|
static bool disp_subaccounts_p(const account_t * account,
|
||||||
const item_predicate<account_t>& disp_pred,
|
const item_predicate<account_t>& disp_pred,
|
||||||
const account_t *& to_show);
|
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));
|
first_line_format.format_elements(output_stream, details_t(&header_entry));
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~format_equity() {
|
|
||||||
flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void flush() {
|
virtual void flush() {
|
||||||
account_t summary(NULL, "Equity:Opening Balances");
|
account_t summary(NULL, "Equity:Opening Balances");
|
||||||
summary.value = - total;
|
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()) {
|
if (i != regexps.begin()) {
|
||||||
config->predicate += "!";
|
config->predicate += "!";
|
||||||
}
|
}
|
||||||
else if (add_account_short_masks &&
|
else if (add_account_short_masks) {
|
||||||
(*i).find(':') == std::string::npos) {
|
if ((*i).find(':') != std::string::npos) {
|
||||||
|
config->show_subtotal = true;
|
||||||
|
} else {
|
||||||
if (! config->display_predicate.empty())
|
if (! config->display_predicate.empty())
|
||||||
config->display_predicate += "&";
|
config->display_predicate += "&";
|
||||||
else if (! config->show_empty)
|
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 += *i;
|
||||||
config->display_predicate += ")/";
|
config->display_predicate += ")/";
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (! account_regexp)
|
if (! account_regexp)
|
||||||
config->predicate += "/";
|
config->predicate += "/";
|
||||||
|
|
@ -257,7 +260,28 @@ int main(int argc, char * argv[], char * envp[])
|
||||||
return 1;
|
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;
|
std::auto_ptr<entry_t> new_entry;
|
||||||
if (command == "e") {
|
if (command == "e") {
|
||||||
|
|
@ -278,7 +302,7 @@ int main(int argc, char * argv[], char * envp[])
|
||||||
regexps_to_predicate(i, args.end(), config);
|
regexps_to_predicate(i, args.end(), config);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compile the predicates
|
// Setup default value for the display predicate
|
||||||
|
|
||||||
if (config->display_predicate.empty()) {
|
if (config->display_predicate.empty()) {
|
||||||
if (command == "b") {
|
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;
|
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 {
|
try {
|
||||||
#ifdef NO_CLEANUP
|
#ifdef NO_CLEANUP
|
||||||
|
|
@ -347,27 +371,7 @@ int main(int argc, char * argv[], char * envp[])
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Configure some option depending on the report type
|
// Setup local and global variables, depending on config settings.
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
std::auto_ptr<std::ostream> output_stream;
|
std::auto_ptr<std::ostream> output_stream;
|
||||||
std::auto_ptr<interval_t> report_interval;
|
std::auto_ptr<interval_t> report_interval;
|
||||||
|
|
@ -458,59 +462,23 @@ int main(int argc, char * argv[], char * envp[])
|
||||||
|
|
||||||
TIMER_START(report_gen);
|
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
|
// Stack up all the formatter needed to fulfills the user's
|
||||||
// requests. Some of these are order dependent, in terms of
|
// requests. Some of these are order dependent, in terms of
|
||||||
// whether calc_transactions occurs before or after them.
|
// whether calc_transactions occurs before or after them.
|
||||||
|
|
||||||
|
std::auto_ptr<item_handler<transaction_t> > formatter;
|
||||||
|
|
||||||
// format_transactions write each transaction received to the
|
// format_transactions write each transaction received to the
|
||||||
// output stream.
|
// 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));
|
formatter.reset(new format_transactions(OUT(), format, nformat));
|
||||||
|
|
||||||
// sort_transactions will sort all the transactions it sees, based
|
// sort_transactions will sort all the transactions it sees, based
|
||||||
|
|
@ -562,6 +530,7 @@ int main(int argc, char * argv[], char * envp[])
|
||||||
interval_begin));
|
interval_begin));
|
||||||
else if (config->days_of_the_week)
|
else if (config->days_of_the_week)
|
||||||
formatter.reset(new dow_transactions(formatter.release()));
|
formatter.reset(new dow_transactions(formatter.release()));
|
||||||
|
}
|
||||||
|
|
||||||
// related_transactions will pass along all transactions related
|
// related_transactions will pass along all transactions related
|
||||||
// to the transaction received. If `show_all_related' is true,
|
// 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
|
// Once the filters are chained, walk `journal's entries and start
|
||||||
// feeding each transaction that matches `predicate' to the chain.
|
// feeding each transaction that matches `predicate' to the chain.
|
||||||
|
if (command == "e")
|
||||||
|
walk_transactions(new_entry->transactions, *formatter);
|
||||||
|
else
|
||||||
walk_entries(journal->entries, *formatter);
|
walk_entries(journal->entries, *formatter);
|
||||||
|
|
||||||
formatter->flush();
|
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
|
// The transaction display flags (dflags) are not recorded in the
|
||||||
// binary cache, and only need to be cleared if the transactions
|
// binary cache, and only need to be cleared if the transactions
|
||||||
// are to be displayed a second time.
|
// are to be displayed a second time.
|
||||||
|
|
@ -590,7 +592,6 @@ int main(int argc, char * argv[], char * envp[])
|
||||||
walk_entries(journal->entries, cleanup);
|
walk_entries(journal->entries, cleanup);
|
||||||
cleanup.flush();
|
cleanup.flush();
|
||||||
#endif
|
#endif
|
||||||
}
|
|
||||||
|
|
||||||
TIMER_STOP(report_gen);
|
TIMER_STOP(report_gen);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,3 +9,4 @@
|
||||||
2004/05/29 Restaurant
|
2004/05/29 Restaurant
|
||||||
Expenses:Food $50.00
|
Expenses:Food $50.00
|
||||||
Liabilities:MasterCard
|
Liabilities:MasterCard
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -110,6 +110,10 @@ transaction_t * parse_transaction(std::istream& in, account_t * account,
|
||||||
in.getline(line, MAX_LINE);
|
in.getline(line, MAX_LINE);
|
||||||
linenum++;
|
linenum++;
|
||||||
|
|
||||||
|
// Skip a possible blank line
|
||||||
|
if (*skip_ws(line) == '\0')
|
||||||
|
return NULL;
|
||||||
|
|
||||||
return parse_transaction_text(line, account, entry);
|
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') {
|
if (peek_next_nonws(in) != '\n') {
|
||||||
in.getline(line, MAX_LINE);
|
in.getline(line, MAX_LINE);
|
||||||
linenum++;
|
linenum++;
|
||||||
throw parse_error(path, linenum,
|
throw parse_error(path, linenum, "Line begins with whitespace");
|
||||||
"Ignoring entry beginning with whitespace");
|
|
||||||
}
|
}
|
||||||
// fall through...
|
// 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();
|
for (amounts_map::const_iterator i = result.amounts.begin();
|
||||||
i != result.amounts.end();
|
i != result.amounts.end();
|
||||||
i++) {
|
i++) {
|
||||||
transaction_t * total_xact = new transaction_t(last_entry,
|
transaction_t * total_xact
|
||||||
totals_account);
|
= new transaction_t(last_entry, totals_account);
|
||||||
xact_temps.push_back(total_xact);
|
xact_temps.push_back(total_xact);
|
||||||
|
|
||||||
total_xact->amount = (*i).second;
|
total_xact->amount = (*i).second;
|
||||||
|
|
|
||||||
33
walk.h
33
walk.h
|
|
@ -18,18 +18,19 @@ struct item_handler {
|
||||||
public:
|
public:
|
||||||
item_handler() : handler(NULL) {}
|
item_handler() : handler(NULL) {}
|
||||||
item_handler(item_handler * _handler) : handler(_handler) {}
|
item_handler(item_handler * _handler) : handler(_handler) {}
|
||||||
virtual ~item_handler() {}
|
|
||||||
virtual void close() {
|
virtual ~item_handler() {
|
||||||
if (handler) {
|
if (handler)
|
||||||
delete handler;
|
delete handler;
|
||||||
handler = NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
virtual void flush() {
|
virtual void flush() {
|
||||||
if (handler)
|
if (handler)
|
||||||
handler->flush();
|
handler->flush();
|
||||||
}
|
}
|
||||||
virtual void operator()(T * item) = 0;
|
virtual void operator()(T * item) {
|
||||||
|
if (handler)
|
||||||
|
(*handler)(item);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
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:
|
public:
|
||||||
|
set_account_value(item_handler<transaction_t> * handler = NULL)
|
||||||
|
: item_handler<transaction_t>(handler) {}
|
||||||
|
|
||||||
virtual void operator()(transaction_t * xact) {
|
virtual void operator()(transaction_t * xact) {
|
||||||
xact->account->value += *xact;
|
xact->account->value += *xact;
|
||||||
xact->account->count++;
|
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)
|
const value_expr_t * _sort_order)
|
||||||
: item_handler<transaction_t>(handler),
|
: item_handler<transaction_t>(handler),
|
||||||
sort_order(_sort_order) {}
|
sort_order(_sort_order) {}
|
||||||
virtual ~sort_transactions() { close(); }
|
|
||||||
|
|
||||||
virtual void flush();
|
virtual void flush();
|
||||||
virtual void operator()(transaction_t * xact) {
|
virtual void operator()(transaction_t * xact) {
|
||||||
|
|
@ -148,8 +154,6 @@ class filter_transactions : public item_handler<transaction_t>
|
||||||
const std::string& predicate)
|
const std::string& predicate)
|
||||||
: item_handler<transaction_t>(handler), pred(predicate) {}
|
: item_handler<transaction_t>(handler), pred(predicate) {}
|
||||||
|
|
||||||
virtual ~filter_transactions() { close(); }
|
|
||||||
|
|
||||||
virtual void operator()(transaction_t * xact) {
|
virtual void operator()(transaction_t * xact) {
|
||||||
if (pred(xact))
|
if (pred(xact))
|
||||||
(*handler)(xact);
|
(*handler)(xact);
|
||||||
|
|
@ -167,8 +171,6 @@ class calc_transactions : public item_handler<transaction_t>
|
||||||
: item_handler<transaction_t>(handler),
|
: item_handler<transaction_t>(handler),
|
||||||
last_xact(NULL), inverted(_inverted) {}
|
last_xact(NULL), inverted(_inverted) {}
|
||||||
|
|
||||||
virtual ~calc_transactions() { close(); }
|
|
||||||
|
|
||||||
virtual void operator()(transaction_t * xact);
|
virtual void operator()(transaction_t * xact);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -189,7 +191,6 @@ class collapse_transactions : public item_handler<transaction_t>
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~collapse_transactions() {
|
virtual ~collapse_transactions() {
|
||||||
close();
|
|
||||||
delete totals_account;
|
delete totals_account;
|
||||||
for (transactions_deque::iterator i = xact_temps.begin();
|
for (transactions_deque::iterator i = xact_temps.begin();
|
||||||
i != xact_temps.end();
|
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) {}
|
changed_values_only(_changed_values_only), last_xact(NULL) {}
|
||||||
|
|
||||||
virtual ~changed_value_transactions() {
|
virtual ~changed_value_transactions() {
|
||||||
close();
|
|
||||||
|
|
||||||
for (entries_deque::iterator i = entry_temps.begin();
|
for (entries_deque::iterator i = entry_temps.begin();
|
||||||
i != entry_temps.end();
|
i != entry_temps.end();
|
||||||
i++)
|
i++)
|
||||||
|
|
@ -275,8 +274,6 @@ class subtotal_transactions : public item_handler<transaction_t>
|
||||||
: item_handler<transaction_t>(handler) {}
|
: item_handler<transaction_t>(handler) {}
|
||||||
|
|
||||||
virtual ~subtotal_transactions() {
|
virtual ~subtotal_transactions() {
|
||||||
close();
|
|
||||||
|
|
||||||
for (entries_deque::iterator i = entry_temps.begin();
|
for (entries_deque::iterator i = entry_temps.begin();
|
||||||
i != entry_temps.end();
|
i != entry_temps.end();
|
||||||
i++)
|
i++)
|
||||||
|
|
@ -342,8 +339,6 @@ class related_transactions : public item_handler<transaction_t>
|
||||||
: item_handler<transaction_t>(handler),
|
: item_handler<transaction_t>(handler),
|
||||||
also_matching(_also_matching) {}
|
also_matching(_also_matching) {}
|
||||||
|
|
||||||
virtual ~related_transactions() { close(); }
|
|
||||||
|
|
||||||
virtual void operator()(transaction_t * xact) {
|
virtual void operator()(transaction_t * xact) {
|
||||||
for (transactions_list::iterator i = xact->entry->transactions.begin();
|
for (transactions_list::iterator i = xact->entry->transactions.begin();
|
||||||
i != xact->entry->transactions.end();
|
i != xact->entry->transactions.end();
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue