changes to value expressions, and to how the display predicate is computed
This commit is contained in:
parent
de39574e89
commit
fadab59e87
8 changed files with 169 additions and 100 deletions
12
config.cc
12
config.cc
|
|
@ -26,7 +26,7 @@ config_t::config_t()
|
||||||
price_db += "/.pricedb";
|
price_db += "/.pricedb";
|
||||||
|
|
||||||
value_expr = "a";
|
value_expr = "a";
|
||||||
total_expr = "T";
|
total_expr = "O";
|
||||||
pricing_leeway = 24 * 3600;
|
pricing_leeway = 24 * 3600;
|
||||||
show_subtotals = true;
|
show_subtotals = true;
|
||||||
show_expanded = false;
|
show_expanded = false;
|
||||||
|
|
@ -301,7 +301,7 @@ OPT_BEGIN(download, "Q") {
|
||||||
|
|
||||||
OPT_BEGIN(quantity, "O") {
|
OPT_BEGIN(quantity, "O") {
|
||||||
config->value_expr = "a";
|
config->value_expr = "a";
|
||||||
config->total_expr = "T";
|
config->total_expr = "O";
|
||||||
} OPT_END(quantity);
|
} OPT_END(quantity);
|
||||||
|
|
||||||
OPT_BEGIN(basis, "B") {
|
OPT_BEGIN(basis, "B") {
|
||||||
|
|
@ -326,23 +326,23 @@ OPT_BEGIN(gain, "G") {
|
||||||
|
|
||||||
OPT_BEGIN(average, "A") {
|
OPT_BEGIN(average, "A") {
|
||||||
config->value_expr = "a";
|
config->value_expr = "a";
|
||||||
config->total_expr = "MT";
|
config->total_expr = "MO";
|
||||||
} OPT_END(average);
|
} OPT_END(average);
|
||||||
|
|
||||||
OPT_BEGIN(deviation, "D") {
|
OPT_BEGIN(deviation, "D") {
|
||||||
config->value_expr = "a";
|
config->value_expr = "a";
|
||||||
config->total_expr = "DMT";
|
config->total_expr = "DMO";
|
||||||
} OPT_END(deviation);
|
} OPT_END(deviation);
|
||||||
|
|
||||||
OPT_BEGIN(trend, "X") {
|
OPT_BEGIN(trend, "X") {
|
||||||
config->value_expr = "a";
|
config->value_expr = "a";
|
||||||
config->total_expr = "MDMT";
|
config->total_expr = "MDMO";
|
||||||
} OPT_END(trend);
|
} OPT_END(trend);
|
||||||
|
|
||||||
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(MT/(1+(((t-d)/(30*86400))<0?0:((t-d)/(30*86400)))))";
|
= "MD(MO/(1+(((t-d)/(30*86400))<0?0:((t-d)/(30*86400)))))";
|
||||||
} OPT_END(weighted_trend);
|
} OPT_END(weighted_trend);
|
||||||
|
|
||||||
} // namespace ledger
|
} // namespace ledger
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,8 @@
|
||||||
|
|
||||||
namespace ledger {
|
namespace ledger {
|
||||||
|
|
||||||
static std::time_t now = std::time(NULL);
|
std::time_t now = std::time(NULL);
|
||||||
struct std::tm * now_tm = std::localtime(&now);
|
struct std::tm * now_tm = std::localtime(&now);
|
||||||
|
|
||||||
static std::time_t base = -1;
|
static std::time_t base = -1;
|
||||||
static int base_year = -1;
|
static int base_year = -1;
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,8 @@
|
||||||
|
|
||||||
#include "ledger.h"
|
#include "ledger.h"
|
||||||
|
|
||||||
|
#include <ctime>
|
||||||
|
|
||||||
namespace ledger {
|
namespace ledger {
|
||||||
|
|
||||||
struct interval_t
|
struct interval_t
|
||||||
|
|
@ -20,6 +22,7 @@ struct interval_t
|
||||||
static interval_t * parse(std::istream& in);
|
static interval_t * parse(std::istream& in);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
extern std::time_t now;
|
||||||
extern struct std::tm * now_tm;
|
extern struct std::tm * now_tm;
|
||||||
|
|
||||||
bool parse_date_mask(const char * date_str, struct std::tm * result);
|
bool parse_date_mask(const char * date_str, struct std::tm * result);
|
||||||
|
|
|
||||||
4
ledger.h
4
ledger.h
|
|
@ -125,6 +125,7 @@ class account_t
|
||||||
|
|
||||||
mutable balance_pair_t value;
|
mutable balance_pair_t value;
|
||||||
mutable balance_pair_t total;
|
mutable balance_pair_t total;
|
||||||
|
mutable unsigned int count; // transactions counted toward total
|
||||||
mutable ident_t ident;
|
mutable ident_t ident;
|
||||||
mutable unsigned short dflags;
|
mutable unsigned short dflags;
|
||||||
mutable std::string _fullname;
|
mutable std::string _fullname;
|
||||||
|
|
@ -135,7 +136,8 @@ class account_t
|
||||||
const std::string& _name = "",
|
const std::string& _name = "",
|
||||||
const std::string& _note = "")
|
const std::string& _note = "")
|
||||||
: parent(_parent), name(_name), note(_note),
|
: parent(_parent), name(_name), note(_note),
|
||||||
depth(parent ? parent->depth + 1 : 0), dflags(0) {}
|
depth(parent ? parent->depth + 1 : 0),
|
||||||
|
count(0), dflags(0) {}
|
||||||
|
|
||||||
~account_t();
|
~account_t();
|
||||||
|
|
||||||
|
|
|
||||||
113
main.cc
113
main.cc
|
|
@ -66,6 +66,66 @@ namespace std {
|
||||||
|
|
||||||
#endif // NO_CLEANUP
|
#endif // NO_CLEANUP
|
||||||
|
|
||||||
|
static void
|
||||||
|
regexps_to_predicate(std::list<std::string>::const_iterator begin,
|
||||||
|
std::list<std::string>::const_iterator end,
|
||||||
|
config_t * config, const bool account_regexp = false,
|
||||||
|
const bool add_account_short_masks = false)
|
||||||
|
{
|
||||||
|
std::vector<std::string> regexps(2);
|
||||||
|
|
||||||
|
// Treat the remaining command-line arguments as regular
|
||||||
|
// expressions, used for refining report results.
|
||||||
|
|
||||||
|
for (std::list<std::string>::const_iterator i = begin;
|
||||||
|
i != end;
|
||||||
|
i++)
|
||||||
|
if ((*i)[0] == '-') {
|
||||||
|
if (! regexps[1].empty())
|
||||||
|
regexps[1] += "|";
|
||||||
|
regexps[1] += (*i).substr(1);
|
||||||
|
}
|
||||||
|
else if ((*i)[0] == '+') {
|
||||||
|
if (! regexps[0].empty())
|
||||||
|
regexps[0] += "|";
|
||||||
|
regexps[0] += (*i).substr(1);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (! regexps[0].empty())
|
||||||
|
regexps[0] += "|";
|
||||||
|
regexps[0] += *i;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (std::vector<std::string>::const_iterator i = regexps.begin();
|
||||||
|
i != regexps.end();
|
||||||
|
i++)
|
||||||
|
if (! (*i).empty()) {
|
||||||
|
if (! config->predicate.empty())
|
||||||
|
config->predicate += "&";
|
||||||
|
|
||||||
|
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 += ")/";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! account_regexp)
|
||||||
|
config->predicate += "/";
|
||||||
|
config->predicate += "/(?:";
|
||||||
|
config->predicate += *i;
|
||||||
|
config->predicate += ")/";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char * argv[], char * envp[])
|
int main(int argc, char * argv[], char * envp[])
|
||||||
{
|
{
|
||||||
std::auto_ptr<journal_t> journal(new journal_t);
|
std::auto_ptr<journal_t> journal(new journal_t);
|
||||||
|
|
@ -123,25 +183,16 @@ int main(int argc, char * argv[], char * envp[])
|
||||||
throw error("Entries not allowed in initialization file");
|
throw error("Entries not allowed in initialization file");
|
||||||
|
|
||||||
if (use_cache && ! config->cache_file.empty()) {
|
if (use_cache && ! config->cache_file.empty()) {
|
||||||
journal->sources.clear(); // remove init_file
|
|
||||||
entry_count += parse_journal_file(config->cache_file, journal.get());
|
entry_count += parse_journal_file(config->cache_file, journal.get());
|
||||||
journal->sources.pop_front(); // remove cache_file
|
if (entry_count == 0) {
|
||||||
|
|
||||||
strings_list exceptions;
|
|
||||||
std::set_difference(journal->sources.begin(), journal->sources.end(),
|
|
||||||
config->files.begin(), config->files.end(),
|
|
||||||
std::back_insert_iterator<strings_list>(exceptions));
|
|
||||||
|
|
||||||
if (entry_count == 0 || exceptions.size() > 0) {
|
|
||||||
journal.reset(new journal_t);
|
journal.reset(new journal_t);
|
||||||
entry_count = 0;
|
|
||||||
cache_dirty = true;
|
cache_dirty = true;
|
||||||
} else {
|
} else {
|
||||||
cache_dirty = false;
|
cache_dirty = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (entry_count == 0)
|
if (entry_count == 0) {
|
||||||
for (strings_list::iterator i = config->files.begin();
|
for (strings_list::iterator i = config->files.begin();
|
||||||
i != config->files.end();
|
i != config->files.end();
|
||||||
i++)
|
i++)
|
||||||
|
|
@ -153,9 +204,10 @@ int main(int argc, char * argv[], char * envp[])
|
||||||
entry_count += parse_journal_file(*i, journal.get());
|
entry_count += parse_journal_file(*i, journal.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! config->price_db.empty())
|
if (! config->price_db.empty())
|
||||||
if (parse_journal_file(config->price_db, journal.get()))
|
if (parse_journal_file(config->price_db, journal.get()))
|
||||||
throw error("Entries not allowed in price history file");
|
throw error("Entries not allowed in price history file");
|
||||||
|
}
|
||||||
|
|
||||||
for (strings_list::iterator i = config->price_settings.begin();
|
for (strings_list::iterator i = config->price_settings.begin();
|
||||||
i != config->price_settings.end();
|
i != config->price_settings.end();
|
||||||
|
|
@ -219,21 +271,11 @@ int main(int argc, char * argv[], char * envp[])
|
||||||
if (*i == "--")
|
if (*i == "--")
|
||||||
break;
|
break;
|
||||||
|
|
||||||
const std::string pred = regexps_to_predicate(arg, i);
|
regexps_to_predicate(arg, i, config, true,
|
||||||
if (! pred.empty()) {
|
command == "b" && ! config->show_expanded &&
|
||||||
if (! config->predicate.empty())
|
config->display_predicate.empty());
|
||||||
config->predicate += "&";
|
if (i != args.end())
|
||||||
config->predicate += pred;
|
regexps_to_predicate(i, args.end(), config);
|
||||||
}
|
|
||||||
|
|
||||||
if (i != args.end()) {
|
|
||||||
const std::string pred = regexps_to_predicate(i, args.end(), false);
|
|
||||||
if (! pred.empty()) {
|
|
||||||
if (! config->predicate.empty())
|
|
||||||
config->predicate += "&";
|
|
||||||
config->predicate += pred;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compile the predicates
|
// Compile the predicates
|
||||||
|
|
@ -242,18 +284,23 @@ int main(int argc, char * argv[], char * envp[])
|
||||||
if (command == "b") {
|
if (command == "b") {
|
||||||
if (! config->show_empty)
|
if (! config->show_empty)
|
||||||
config->display_predicate = "T";
|
config->display_predicate = "T";
|
||||||
|
if (! config->show_expanded) {
|
||||||
if (! config->show_expanded && config->predicate.empty()) {
|
|
||||||
if (! config->display_predicate.empty())
|
if (! config->display_predicate.empty())
|
||||||
config->display_predicate += "&";
|
config->display_predicate += "&";
|
||||||
config->display_predicate += "!n";
|
config->display_predicate += "!l";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (command == "E") {
|
else if (command == "E") {
|
||||||
config->display_predicate = "a";
|
config->display_predicate = "t";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG_ENABLED
|
||||||
|
DEBUG_PRINT("ledger.main.predicates", "predicate: " << config->predicate);
|
||||||
|
DEBUG_PRINT("ledger.main.predicates",
|
||||||
|
"disp-pred: " << config->display_predicate);
|
||||||
|
#endif
|
||||||
|
|
||||||
// Compile the sorting criteria
|
// Compile the sorting criteria
|
||||||
|
|
||||||
std::auto_ptr<value_expr_t> sort_order;
|
std::auto_ptr<value_expr_t> sort_order;
|
||||||
|
|
|
||||||
119
valexpr.cc
119
valexpr.cc
|
|
@ -1,4 +1,5 @@
|
||||||
#include "valexpr.h"
|
#include "valexpr.h"
|
||||||
|
#include "format.h"
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
#include "datetime.h"
|
#include "datetime.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
|
|
@ -119,15 +120,32 @@ void value_expr_t::compute(balance_t& result, const details_t& details) const
|
||||||
result = details.account->total.cost;
|
result = details.account->total.cost;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case VALUE_EXPR:
|
||||||
|
#ifdef NO_CLEANUP
|
||||||
|
assert(format_t::value_expr);
|
||||||
|
#else
|
||||||
|
assert(format_t::value_expr.get());
|
||||||
|
#endif
|
||||||
|
format_t::value_expr->compute(result, details);
|
||||||
|
break;
|
||||||
|
case TOTAL_EXPR:
|
||||||
|
#ifdef NO_CLEANUP
|
||||||
|
assert(format_t::total_expr);
|
||||||
|
#else
|
||||||
|
assert(format_t::total_expr.get());
|
||||||
|
#endif
|
||||||
|
format_t::total_expr->compute(result, details);
|
||||||
|
break;
|
||||||
|
|
||||||
case DATE:
|
case DATE:
|
||||||
if (details.entry)
|
if (details.entry)
|
||||||
result = (unsigned int) details.entry->date;
|
result = (unsigned int) details.entry->date;
|
||||||
else
|
else
|
||||||
result = (unsigned int) std::time(NULL);
|
result = (unsigned int) now;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TODAY:
|
case TODAY:
|
||||||
result = (unsigned int) std::time(NULL);
|
result = (unsigned int) now;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CLEARED:
|
case CLEARED:
|
||||||
|
|
@ -169,6 +187,11 @@ void value_expr_t::compute(balance_t& result, const details_t& details) const
|
||||||
case INDEX:
|
case INDEX:
|
||||||
if (details.xact)
|
if (details.xact)
|
||||||
result = details.xact->index + 1;
|
result = details.xact->index + 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DEPTH:
|
||||||
|
if (details.xact)
|
||||||
|
result = details.xact->account->depth - 1;
|
||||||
else if (details.account)
|
else if (details.account)
|
||||||
result = details.account->depth - 1;
|
result = details.account->depth - 1;
|
||||||
break;
|
break;
|
||||||
|
|
@ -179,6 +202,11 @@ void value_expr_t::compute(balance_t& result, const details_t& details) const
|
||||||
left->compute(result, details);
|
left->compute(result, details);
|
||||||
result /= amount_t(details.xact->index + 1);
|
result /= amount_t(details.xact->index + 1);
|
||||||
}
|
}
|
||||||
|
else if (details.account && details.account->count) {
|
||||||
|
assert(left);
|
||||||
|
left->compute(result, details);
|
||||||
|
result /= amount_t(details.account->count);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case F_NEG:
|
case F_NEG:
|
||||||
|
|
@ -214,6 +242,12 @@ void value_expr_t::compute(balance_t& result, const details_t& details) const
|
||||||
result = mask->match(details.account->fullname());
|
result = mask->match(details.account->fullname());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case F_SHORT_ACCOUNT_MASK:
|
||||||
|
assert(mask);
|
||||||
|
if (details.account)
|
||||||
|
result = mask->match(details.account->name);
|
||||||
|
break;
|
||||||
|
|
||||||
case F_VALUE: {
|
case F_VALUE: {
|
||||||
assert(left);
|
assert(left);
|
||||||
left->compute(result, details);
|
left->compute(result, details);
|
||||||
|
|
@ -225,18 +259,18 @@ void value_expr_t::compute(balance_t& result, const details_t& details) const
|
||||||
if (details.entry)
|
if (details.entry)
|
||||||
moment = details.entry->date;
|
moment = details.entry->date;
|
||||||
else
|
else
|
||||||
moment = std::time(NULL);
|
moment = now;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TODAY:
|
case TODAY:
|
||||||
moment = std::time(NULL);
|
moment = now;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw compute_error("Invalid date passed to P(value,date)");
|
throw compute_error("Invalid date passed to P(value,date)");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
moment = std::time(NULL);
|
moment = now;
|
||||||
}
|
}
|
||||||
result = result.value(moment);
|
result = result.value(moment);
|
||||||
break;
|
break;
|
||||||
|
|
@ -359,16 +393,21 @@ value_expr_t * parse_value_term(std::istream& in)
|
||||||
case 'a': node = new value_expr_t(value_expr_t::AMOUNT); break;
|
case 'a': node = new value_expr_t(value_expr_t::AMOUNT); break;
|
||||||
case 'c': node = new value_expr_t(value_expr_t::COST); break;
|
case 'c': node = new value_expr_t(value_expr_t::COST); break;
|
||||||
case 'd': node = new value_expr_t(value_expr_t::DATE); break;
|
case 'd': node = new value_expr_t(value_expr_t::DATE); break;
|
||||||
case 't': node = new value_expr_t(value_expr_t::TODAY); break;
|
case 'N': node = new value_expr_t(value_expr_t::TODAY); break;
|
||||||
case 'X': node = new value_expr_t(value_expr_t::CLEARED); break;
|
case 'X': node = new value_expr_t(value_expr_t::CLEARED); break;
|
||||||
case 'R': node = new value_expr_t(value_expr_t::REAL); break;
|
case 'R': node = new value_expr_t(value_expr_t::REAL); break;
|
||||||
case 'n': node = new value_expr_t(value_expr_t::INDEX); break;
|
case 'n': node = new value_expr_t(value_expr_t::INDEX); break;
|
||||||
|
case 'l': node = new value_expr_t(value_expr_t::DEPTH); break;
|
||||||
case 'B': node = new value_expr_t(value_expr_t::BALANCE); break;
|
case 'B': node = new value_expr_t(value_expr_t::BALANCE); break;
|
||||||
case 'T': node = new value_expr_t(value_expr_t::TOTAL); break;
|
case 'O': node = new value_expr_t(value_expr_t::TOTAL); break;
|
||||||
case 'C': node = new value_expr_t(value_expr_t::COST_TOTAL); break;
|
case 'C': node = new value_expr_t(value_expr_t::COST_TOTAL); break;
|
||||||
|
|
||||||
|
// Relating to format_t
|
||||||
|
case 't': node = new value_expr_t(value_expr_t::VALUE_EXPR); break;
|
||||||
|
case 'T': node = new value_expr_t(value_expr_t::TOTAL_EXPR); break;
|
||||||
|
|
||||||
// Compound terms
|
// Compound terms
|
||||||
case 'v': node = parse_value_expr("P(a,d)"); break;
|
case 'v': node = parse_value_expr("P(t,d)"); break;
|
||||||
case 'V': node = parse_value_term("P(T,d)"); break;
|
case 'V': node = parse_value_term("P(T,d)"); break;
|
||||||
case 'g': node = parse_value_expr("v-c"); break;
|
case 'g': node = parse_value_expr("v-c"); break;
|
||||||
case 'G': node = parse_value_expr("V-C"); break;
|
case 'G': node = parse_value_expr("V-C"); break;
|
||||||
|
|
@ -423,13 +462,20 @@ value_expr_t * parse_value_term(std::istream& in)
|
||||||
|
|
||||||
// Other
|
// Other
|
||||||
case '/': {
|
case '/': {
|
||||||
bool payee_mask = false;
|
bool payee_mask = false;
|
||||||
|
bool short_account_mask = false;
|
||||||
|
|
||||||
c = peek_next_nonws(in);
|
c = peek_next_nonws(in);
|
||||||
if (c == '/') {
|
if (c == '/') {
|
||||||
payee_mask = true;
|
|
||||||
in.get(c);
|
in.get(c);
|
||||||
c = in.peek();
|
c = in.peek();
|
||||||
|
if (c == '/') {
|
||||||
|
in.get(c);
|
||||||
|
c = in.peek();
|
||||||
|
short_account_mask = true;
|
||||||
|
} else {
|
||||||
|
payee_mask = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static char buf[4096];
|
static char buf[4096];
|
||||||
|
|
@ -438,8 +484,10 @@ value_expr_t * parse_value_term(std::istream& in)
|
||||||
throw value_expr_error("Missing closing '/'");
|
throw value_expr_error("Missing closing '/'");
|
||||||
|
|
||||||
in.get(c);
|
in.get(c);
|
||||||
node = new value_expr_t(payee_mask ? value_expr_t::F_PAYEE_MASK :
|
node = new value_expr_t(short_account_mask ?
|
||||||
value_expr_t::F_ACCOUNT_MASK);
|
value_expr_t::F_SHORT_ACCOUNT_MASK :
|
||||||
|
(payee_mask ? value_expr_t::F_PAYEE_MASK :
|
||||||
|
value_expr_t::F_ACCOUNT_MASK));
|
||||||
node->mask = new mask_t(buf);
|
node->mask = new mask_t(buf);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -664,47 +712,6 @@ value_expr_t * parse_value_expr(std::istream& in)
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string regexps_to_predicate(std::list<std::string>::const_iterator begin,
|
|
||||||
std::list<std::string>::const_iterator end,
|
|
||||||
const bool account_regexp)
|
|
||||||
{
|
|
||||||
std::vector<std::string> regexps(2);
|
|
||||||
std::string pred;
|
|
||||||
|
|
||||||
// Treat the remaining command-line arguments as regular
|
|
||||||
// expressions, used for refining report results.
|
|
||||||
|
|
||||||
for (std::list<std::string>::const_iterator i = begin;
|
|
||||||
i != end;
|
|
||||||
i++)
|
|
||||||
if ((*i)[0] == '-') {
|
|
||||||
if (! regexps[1].empty())
|
|
||||||
regexps[1] += "|";
|
|
||||||
regexps[1] += (*i).substr(1);
|
|
||||||
} else {
|
|
||||||
if (! regexps[0].empty())
|
|
||||||
regexps[0] += "|";
|
|
||||||
regexps[0] += *i;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (std::vector<std::string>::const_iterator i = regexps.begin();
|
|
||||||
i != regexps.end();
|
|
||||||
i++)
|
|
||||||
if (! (*i).empty()) {
|
|
||||||
if (! pred.empty())
|
|
||||||
pred += "&";
|
|
||||||
if (i != regexps.begin())
|
|
||||||
pred += "!";
|
|
||||||
if (! account_regexp)
|
|
||||||
pred += "/";
|
|
||||||
pred += "/(?:";
|
|
||||||
pred += *i;
|
|
||||||
pred += ")/";
|
|
||||||
}
|
|
||||||
|
|
||||||
return pred;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef DEBUG_ENABLED
|
#ifdef DEBUG_ENABLED
|
||||||
|
|
||||||
void dump_value_expr(std::ostream& out, const value_expr_t * node)
|
void dump_value_expr(std::ostream& out, const value_expr_t * node)
|
||||||
|
|
@ -724,6 +731,7 @@ void dump_value_expr(std::ostream& out, const value_expr_t * node)
|
||||||
case value_expr_t::CLEARED: out << "CLEARED"; break;
|
case value_expr_t::CLEARED: out << "CLEARED"; break;
|
||||||
case value_expr_t::REAL: out << "REAL"; break;
|
case value_expr_t::REAL: out << "REAL"; break;
|
||||||
case value_expr_t::INDEX: out << "INDEX"; break;
|
case value_expr_t::INDEX: out << "INDEX"; break;
|
||||||
|
case value_expr_t::DEPTH: out << "DEPTH"; break;
|
||||||
case value_expr_t::BALANCE: out << "BALANCE"; break;
|
case value_expr_t::BALANCE: out << "BALANCE"; break;
|
||||||
case value_expr_t::COST_BALANCE: out << "COST_BALANCE"; break;
|
case value_expr_t::COST_BALANCE: out << "COST_BALANCE"; break;
|
||||||
case value_expr_t::TOTAL: out << "TOTAL"; break;
|
case value_expr_t::TOTAL: out << "TOTAL"; break;
|
||||||
|
|
@ -763,6 +771,11 @@ void dump_value_expr(std::ostream& out, const value_expr_t * node)
|
||||||
out << "A_MASK(" << node->mask->pattern << ")";
|
out << "A_MASK(" << node->mask->pattern << ")";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case value_expr_t::F_SHORT_ACCOUNT_MASK:
|
||||||
|
assert(node->mask);
|
||||||
|
out << "A_SMASK(" << node->mask->pattern << ")";
|
||||||
|
break;
|
||||||
|
|
||||||
case value_expr_t::F_VALUE:
|
case value_expr_t::F_VALUE:
|
||||||
out << "VALUE(";
|
out << "VALUE(";
|
||||||
dump_value_expr(out, node->left);
|
dump_value_expr(out, node->left);
|
||||||
|
|
|
||||||
12
valexpr.h
12
valexpr.h
|
|
@ -52,7 +52,8 @@ struct value_expr_t
|
||||||
TODAY,
|
TODAY,
|
||||||
CLEARED,
|
CLEARED,
|
||||||
REAL,
|
REAL,
|
||||||
INDEX, // for accounts, this is the DEPTH
|
INDEX,
|
||||||
|
DEPTH,
|
||||||
|
|
||||||
// Item totals
|
// Item totals
|
||||||
BALANCE,
|
BALANCE,
|
||||||
|
|
@ -60,6 +61,10 @@ struct value_expr_t
|
||||||
TOTAL,
|
TOTAL,
|
||||||
COST_TOTAL,
|
COST_TOTAL,
|
||||||
|
|
||||||
|
// Relating to format_t
|
||||||
|
VALUE_EXPR,
|
||||||
|
TOTAL_EXPR,
|
||||||
|
|
||||||
// Functions
|
// Functions
|
||||||
F_ARITH_MEAN,
|
F_ARITH_MEAN,
|
||||||
F_VALUE,
|
F_VALUE,
|
||||||
|
|
@ -68,6 +73,7 @@ struct value_expr_t
|
||||||
F_STRIP,
|
F_STRIP,
|
||||||
F_PAYEE_MASK,
|
F_PAYEE_MASK,
|
||||||
F_ACCOUNT_MASK,
|
F_ACCOUNT_MASK,
|
||||||
|
F_SHORT_ACCOUNT_MASK,
|
||||||
|
|
||||||
// Binary operators
|
// Binary operators
|
||||||
O_ADD,
|
O_ADD,
|
||||||
|
|
@ -174,10 +180,6 @@ class item_predicate
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
std::string regexps_to_predicate(std::list<std::string>::const_iterator begin,
|
|
||||||
std::list<std::string>::const_iterator end,
|
|
||||||
const bool account_regexp = true);
|
|
||||||
|
|
||||||
} // namespace report
|
} // namespace report
|
||||||
|
|
||||||
#endif // _REPORT_H
|
#endif // _REPORT_H
|
||||||
|
|
|
||||||
2
walk.h
2
walk.h
|
|
@ -117,6 +117,7 @@ class add_to_account_value : public item_handler<transaction_t>
|
||||||
public:
|
public:
|
||||||
virtual void operator()(transaction_t * xact) {
|
virtual void operator()(transaction_t * xact) {
|
||||||
xact->account->value += *xact;
|
xact->account->value += *xact;
|
||||||
|
xact->account->count++;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -368,6 +369,7 @@ inline void sum_accounts(account_t * account) {
|
||||||
i++) {
|
i++) {
|
||||||
sum_accounts((*i).second);
|
sum_accounts((*i).second);
|
||||||
account->total += (*i).second->total;
|
account->total += (*i).second->total;
|
||||||
|
account->count += (*i).second->count;
|
||||||
}
|
}
|
||||||
account->total += account->value;
|
account->total += account->value;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue