many more formatting changes

This commit is contained in:
John Wiegley 2004-08-11 22:54:42 -04:00
parent a999372bef
commit a77c20a772
7 changed files with 430 additions and 432 deletions

View file

@ -33,8 +33,8 @@ std::string partial_account_name(const account_t * account)
return name; return name;
} }
std::auto_ptr<node_t> format_t::value_expr; std::auto_ptr<value_expr_t> format_t::value_expr;
std::auto_ptr<node_t> format_t::total_expr; std::auto_ptr<value_expr_t> format_t::total_expr;
element_t * format_t::parse_elements(const std::string& fmt) element_t * format_t::parse_elements(const std::string& fmt)
{ {
@ -99,7 +99,7 @@ element_t * format_t::parse_elements(const std::string& fmt)
throw format_error("Missing ')'"); throw format_error("Missing ')'");
current->type = element_t::VALUE_EXPR; current->type = element_t::VALUE_EXPR;
current->val_expr = parse_expr(num); current->val_expr = parse_value_expr(num);
break; break;
case '[': case '[':

View file

@ -29,13 +29,13 @@ struct element_t
SPACER SPACER
}; };
bool align_left; bool align_left;
unsigned int min_width; unsigned int min_width;
unsigned int max_width; unsigned int max_width;
kind_t type; kind_t type;
std::string chars; std::string chars;
node_t * val_expr; value_expr_t * val_expr;
struct element_t * next; struct element_t * next;
@ -52,8 +52,8 @@ struct format_t
{ {
element_t * elements; element_t * elements;
static std::auto_ptr<node_t> value_expr; static std::auto_ptr<value_expr_t> value_expr;
static std::auto_ptr<node_t> total_expr; static std::auto_ptr<value_expr_t> total_expr;
format_t(const std::string& _format) : elements(NULL) { format_t(const std::string& _format) : elements(NULL) {
reset(_format); reset(_format);
@ -107,17 +107,14 @@ class format_transactions : public item_handler<transaction_t>
} }
virtual void operator()(transaction_t * xact) { virtual void operator()(transaction_t * xact) {
xact->dflags |= TRANSACTION_DISPLAYED; if (last_entry != xact->entry) {
// This makes the assumption that transactions from a single entry
// are always grouped together.
if (last_entry != xact->entry)
first_line_format.format_elements(output_stream, details_t(xact)); first_line_format.format_elements(output_stream, details_t(xact));
else last_entry = xact->entry;
} else {
next_lines_format.format_elements(output_stream, details_t(xact)); next_lines_format.format_elements(output_stream, details_t(xact));
}
last_entry = xact->entry; xact->dflags |= TRANSACTION_DISPLAYED;
} }
}; };

72
main.cc
View file

@ -159,7 +159,7 @@ int main(int argc, char * argv[])
std::auto_ptr<journal_t> journal(new journal_t); std::auto_ptr<journal_t> journal(new journal_t);
std::list<std::string> files; std::list<std::string> files;
std::auto_ptr<node_t> sort_order; std::auto_ptr<value_expr_t> sort_order;
std::string predicate; std::string predicate;
std::string display_predicate; std::string display_predicate;
@ -538,31 +538,29 @@ int main(int argc, char * argv[])
// Compile the sorting string // Compile the sorting string
if (! sort_string.empty()) if (! sort_string.empty())
sort_order.reset(parse_expr(sort_string)); sort_order.reset(parse_value_expr(sort_string));
// Setup the meaning of %t and %T, used in format strings // Setup the meaning of %t and %T, used in format strings
format_t::value_expr.reset(parse_expr(value_expr)); format_t::value_expr.reset(parse_value_expr(value_expr));
format_t::total_expr.reset(parse_expr(total_expr)); format_t::total_expr.reset(parse_value_expr(total_expr));
// Now handle the command that was identified above. // Now handle the command that was identified above.
unsigned int xact_display_flags = MATCHING_TRANSACTIONS; bool show_all_related = false;
if (command == "p" || command == "e") { if (command == "p" || command == "e") {
xact_display_flags |= OTHER_TRANSACTIONS; show_related = show_all_related = true;
show_expanded = true; show_expanded = true;
} }
else if (command == "E") { else if (command == "E") {
show_expanded = true; show_expanded = true;
} }
else if (show_related) { else if (show_related) {
if (command == "r") { if (command == "r")
xact_display_flags = OTHER_TRANSACTIONS;
show_inverted = true; show_inverted = true;
} else { else
xact_display_flags |= OTHER_TRANSACTIONS; show_all_related = true;
}
} }
const char * f; const char * f;
@ -591,9 +589,21 @@ int main(int argc, char * argv[])
format_t nformat(next_lines_format); format_t nformat(next_lines_format);
if (command == "b") { if (command == "b") {
format_account formatter(std::cout, format, display_predicate); std::auto_ptr<item_handler<transaction_t> > formatter;
walk_accounts(journal->master, formatter, predicate,
xact_display_flags, show_subtotals, sort_order.get()); formatter.reset(new add_to_account_value);
if (show_related)
formatter.reset(new related_transactions(formatter.release(),
show_all_related));
formatter.reset(new filter_transactions(formatter.release(),
predicate));
walk_entries(journal->entries, *formatter.get());
format_account acct_formatter(std::cout, format, display_predicate);
walk_accounts(journal->master, acct_formatter, show_subtotals,
sort_order.get());
if (format_account::disp_subaccounts_p(journal->master)) { if (format_account::disp_subaccounts_p(journal->master)) {
std::string end_format = "--------------------\n"; std::string end_format = "--------------------\n";
@ -602,17 +612,16 @@ int main(int argc, char * argv[])
} }
} }
else if (command == "E") { else if (command == "E") {
format_equity formatter(std::cout, format, nformat, display_predicate); add_to_account_value formatter;
walk_accounts(journal->master, formatter, predicate, walk_entries(journal->entries, formatter);
xact_display_flags, true, sort_order.get());
format_equity acct_formatter(std::cout, format, nformat,
display_predicate);
walk_accounts(journal->master, acct_formatter, true, sort_order.get());
} }
else if (command == "e") { else if (command == "e") {
format_transactions formatter(std::cout, format, nformat); format_transactions formatter(std::cout, format, nformat);
walk_transactions(new_entry->transactions, formatter);
for (transactions_list::iterator i = new_entry->transactions.begin();
i != new_entry->transactions.end();
i++)
handle_transaction(*i, formatter, xact_display_flags);
} }
else { else {
std::auto_ptr<item_handler<transaction_t> > formatter; std::auto_ptr<item_handler<transaction_t> > formatter;
@ -667,10 +676,23 @@ int main(int argc, char * argv[])
formatter.reset(new interval_transactions(formatter.release(), 0, formatter.reset(new interval_transactions(formatter.release(), 0,
interval_t(9676800, 0, 0))); interval_t(9676800, 0, 0)));
// 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 (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(), predicate));
// 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.
walk_entries(journal->entries.begin(), journal->entries.end(), walk_entries(journal->entries.begin(), journal->entries.end(),
*formatter.get(), predicate, xact_display_flags); *formatter.get());
} }
// Save the cache, if need be // Save the cache, if need be
@ -679,10 +701,6 @@ int main(int argc, char * argv[])
if (const char * p = std::getenv("LEDGER_CACHE")) { if (const char * p = std::getenv("LEDGER_CACHE")) {
std::ofstream outstr(p); std::ofstream outstr(p);
assert(std::getenv("LEDGER")); assert(std::getenv("LEDGER"));
#if 0
clear_transaction_display_flags(journal->entries.begin(),
journal->entries.end());
#endif
write_binary_journal(outstr, journal.get(), std::getenv("LEDGER")); write_binary_journal(outstr, journal.get(), std::getenv("LEDGER"));
} }

View file

@ -56,45 +56,8 @@ mask_t::~mask_t() {
pcre_free((pcre *)regexp); pcre_free((pcre *)regexp);
} }
#if 1
bool matches(const masks_list& regexps, const std::string& str, void value_expr_t::compute(balance_t& result, const details_t& details) const
bool * by_exclusion)
{
if (regexps.empty())
return false;
bool match = false;
bool definite = false;
for (masks_list::const_iterator r = regexps.begin();
r != regexps.end();
r++) {
static int ovec[30];
int result = pcre_exec((pcre *)(*r).regexp, NULL,
str.c_str(), str.length(), 0, 0, ovec, 30);
if (result >= 0) {
match = ! (*r).exclude;
definite = true;
}
else if ((*r).exclude) {
if (! match)
match = ! definite;
}
else {
definite = true;
}
}
if (by_exclusion)
*by_exclusion = match && ! definite && by_exclusion;
return match;
}
#endif
void node_t::compute(balance_t& result, const details_t& details) const
{ {
switch (type) { switch (type) {
case CONSTANT_A: case CONSTANT_A:
@ -351,16 +314,16 @@ inline char peek_next_nonws(std::istream& in)
return c; return c;
} }
node_t * parse_term(std::istream& in); value_expr_t * parse_value_term(std::istream& in);
inline node_t * parse_term(const char * p) { inline value_expr_t * parse_value_term(const char * p) {
std::istringstream stream(p); std::istringstream stream(p);
return parse_term(stream); return parse_value_term(stream);
} }
node_t * parse_term(std::istream& in) value_expr_t * parse_value_term(std::istream& in)
{ {
node_t * node = NULL; value_expr_t * node = NULL;
char c = peek_next_nonws(in); char c = peek_next_nonws(in);
if (std::isdigit(c) || c == '.' || c == '{') { if (std::isdigit(c) || c == '.' || c == '{') {
@ -387,7 +350,7 @@ node_t * parse_term(std::istream& in)
} }
if (! ident.empty()) { if (! ident.empty()) {
node = new node_t(node_t::CONSTANT_A); node = new value_expr_t(value_expr_t::CONSTANT_A);
node->constant_a.parse(ident); node->constant_a.parse(ident);
} }
return node; return node;
@ -396,62 +359,62 @@ node_t * parse_term(std::istream& in)
in.get(c); in.get(c);
switch (c) { switch (c) {
// Basic terms // Basic terms
case 'a': node = new node_t(node_t::AMOUNT); break; case 'a': node = new value_expr_t(value_expr_t::AMOUNT); break;
case 'c': node = new node_t(node_t::COST); break; case 'c': node = new value_expr_t(value_expr_t::COST); break;
case 'd': node = new node_t(node_t::DATE); break; case 'd': node = new value_expr_t(value_expr_t::DATE); break;
case 'X': node = new node_t(node_t::CLEARED); break; case 'X': node = new value_expr_t(value_expr_t::CLEARED); break;
case 'R': node = new node_t(node_t::REAL); break; case 'R': node = new value_expr_t(value_expr_t::REAL); break;
case 'n': node = new node_t(node_t::INDEX); break; case 'n': node = new value_expr_t(value_expr_t::INDEX); break;
case 'B': node = new node_t(node_t::BALANCE); break; case 'B': node = new value_expr_t(value_expr_t::BALANCE); break;
case 'T': node = new node_t(node_t::TOTAL); break; case 'T': node = new value_expr_t(value_expr_t::TOTAL); break;
case 'C': node = new node_t(node_t::COST_TOTAL); break; case 'C': node = new value_expr_t(value_expr_t::COST_TOTAL); break;
// Compound terms // Compound terms
case 'v': node = parse_expr("P(a,d)"); break; case 'v': node = parse_value_expr("P(a,d)"); break;
case 'V': node = parse_term("P(T,d)"); break; case 'V': node = parse_value_term("P(T,d)"); break;
case 'g': node = parse_expr("v-c"); break; case 'g': node = parse_value_expr("v-c"); break;
case 'G': node = parse_expr("V-C"); break; case 'G': node = parse_value_expr("V-C"); break;
case 'o': node = parse_expr("d-b"); break; case 'o': node = parse_value_expr("d-b"); break;
case 'w': node = parse_expr("e-d"); break; case 'w': node = parse_value_expr("e-d"); break;
// Functions // Functions
case '-': case '-':
node = new node_t(node_t::F_NEG); node = new value_expr_t(value_expr_t::F_NEG);
node->left = parse_term(in); node->left = parse_value_term(in);
break; break;
case 'A': case 'A':
node = new node_t(node_t::F_ABS); node = new value_expr_t(value_expr_t::F_ABS);
node->left = parse_term(in); node->left = parse_value_term(in);
break; break;
case 'M': case 'M':
node = new node_t(node_t::F_ARITH_MEAN); node = new value_expr_t(value_expr_t::F_ARITH_MEAN);
node->left = parse_term(in); node->left = parse_value_term(in);
break; break;
case 'D': { case 'D': {
node = new node_t(node_t::O_SUB); node = new value_expr_t(value_expr_t::O_SUB);
node->left = parse_term("a"); node->left = parse_value_term("a");
node->right = parse_term(in); node->right = parse_value_term(in);
break; break;
} }
case 'P': case 'P':
node = new node_t(node_t::F_VALUE); node = new value_expr_t(value_expr_t::F_VALUE);
if (peek_next_nonws(in) == '(') { if (peek_next_nonws(in) == '(') {
in.get(c); in.get(c);
node->left = parse_expr(in); node->left = parse_value_expr(in);
if (peek_next_nonws(in) == ',') { if (peek_next_nonws(in) == ',') {
in.get(c); in.get(c);
node->right = parse_expr(in); node->right = parse_value_expr(in);
} }
if (peek_next_nonws(in) == ')') if (peek_next_nonws(in) == ')')
in.get(c); in.get(c);
else else
throw expr_error("Missing ')'"); throw expr_error("Missing ')'");
} else { } else {
node->left = parse_term(in); node->left = parse_value_term(in);
} }
break; break;
@ -477,8 +440,8 @@ node_t * parse_term(std::istream& in)
if (c == '/') { if (c == '/') {
in.get(c); in.get(c);
node = new node_t(payee_mask ? node = new value_expr_t(payee_mask ?
node_t::F_PAYEE_MASK : node_t::F_ACCOUNT_MASK); value_expr_t::F_PAYEE_MASK : value_expr_t::F_ACCOUNT_MASK);
node->mask = new mask_t(ident); node->mask = new mask_t(ident);
} else { } else {
throw expr_error("Missing closing '/'"); throw expr_error("Missing closing '/'");
@ -487,7 +450,7 @@ node_t * parse_term(std::istream& in)
} }
case '(': case '(':
node = parse_expr(in); node = parse_value_expr(in);
if (peek_next_nonws(in) == ')') if (peek_next_nonws(in) == ')')
in.get(c); in.get(c);
else else
@ -505,7 +468,7 @@ node_t * parse_term(std::istream& in)
} }
if (c == ']') { if (c == ']') {
in.get(c); in.get(c);
node = new node_t(node_t::CONSTANT_T); node = new value_expr_t(value_expr_t::CONSTANT_T);
if (! parse_date(ident.c_str(), &node->constant_t)) if (! parse_date(ident.c_str(), &node->constant_t))
throw expr_error("Failed to parse date"); throw expr_error("Failed to parse date");
} else { } else {
@ -522,11 +485,11 @@ node_t * parse_term(std::istream& in)
return node; return node;
} }
node_t * parse_mul_expr(std::istream& in) value_expr_t * parse_mul_expr(std::istream& in)
{ {
node_t * node = NULL; value_expr_t * node = NULL;
node = parse_term(in); node = parse_value_term(in);
if (node && ! in.eof()) { if (node && ! in.eof()) {
char c = peek_next_nonws(in); char c = peek_next_nonws(in);
@ -534,18 +497,18 @@ node_t * parse_mul_expr(std::istream& in)
in.get(c); in.get(c);
switch (c) { switch (c) {
case '*': { case '*': {
node_t * prev = node; value_expr_t * prev = node;
node = new node_t(node_t::O_MUL); node = new value_expr_t(value_expr_t::O_MUL);
node->left = prev; node->left = prev;
node->right = parse_term(in); node->right = parse_value_term(in);
break; break;
} }
case '/': { case '/': {
node_t * prev = node; value_expr_t * prev = node;
node = new node_t(node_t::O_DIV); node = new value_expr_t(value_expr_t::O_DIV);
node->left = prev; node->left = prev;
node->right = parse_term(in); node->right = parse_value_term(in);
break; break;
} }
} }
@ -556,9 +519,9 @@ node_t * parse_mul_expr(std::istream& in)
return node; return node;
} }
node_t * parse_add_expr(std::istream& in) value_expr_t * parse_add_expr(std::istream& in)
{ {
node_t * node = NULL; value_expr_t * node = NULL;
node = parse_mul_expr(in); node = parse_mul_expr(in);
@ -568,16 +531,16 @@ node_t * parse_add_expr(std::istream& in)
in.get(c); in.get(c);
switch (c) { switch (c) {
case '+': { case '+': {
node_t * prev = node; value_expr_t * prev = node;
node = new node_t(node_t::O_ADD); node = new value_expr_t(value_expr_t::O_ADD);
node->left = prev; node->left = prev;
node->right = parse_mul_expr(in); node->right = parse_mul_expr(in);
break; break;
} }
case '-': { case '-': {
node_t * prev = node; value_expr_t * prev = node;
node = new node_t(node_t::O_SUB); node = new value_expr_t(value_expr_t::O_SUB);
node->left = prev; node->left = prev;
node->right = parse_mul_expr(in); node->right = parse_mul_expr(in);
break; break;
@ -590,14 +553,14 @@ node_t * parse_add_expr(std::istream& in)
return node; return node;
} }
node_t * parse_logic_expr(std::istream& in) value_expr_t * parse_logic_expr(std::istream& in)
{ {
node_t * node = NULL; value_expr_t * node = NULL;
if (peek_next_nonws(in) == '!') { if (peek_next_nonws(in) == '!') {
char c; char c;
in.get(c); in.get(c);
node = new node_t(node_t::O_NOT); node = new value_expr_t(value_expr_t::O_NOT);
node->left = parse_logic_expr(in); node->left = parse_logic_expr(in);
return node; return node;
} }
@ -610,19 +573,19 @@ node_t * parse_logic_expr(std::istream& in)
in.get(c); in.get(c);
switch (c) { switch (c) {
case '=': { case '=': {
node_t * prev = node; value_expr_t * prev = node;
node = new node_t(node_t::O_EQ); node = new value_expr_t(value_expr_t::O_EQ);
node->left = prev; node->left = prev;
node->right = parse_add_expr(in); node->right = parse_add_expr(in);
break; break;
} }
case '<': { case '<': {
node_t * prev = node; value_expr_t * prev = node;
node = new node_t(node_t::O_LT); node = new value_expr_t(value_expr_t::O_LT);
if (peek_next_nonws(in) == '=') { if (peek_next_nonws(in) == '=') {
in.get(c); in.get(c);
node->type = node_t::O_LTE; node->type = value_expr_t::O_LTE;
} }
node->left = prev; node->left = prev;
node->right = parse_add_expr(in); node->right = parse_add_expr(in);
@ -630,11 +593,11 @@ node_t * parse_logic_expr(std::istream& in)
} }
case '>': { case '>': {
node_t * prev = node; value_expr_t * prev = node;
node = new node_t(node_t::O_GT); node = new value_expr_t(value_expr_t::O_GT);
if (peek_next_nonws(in) == '=') { if (peek_next_nonws(in) == '=') {
in.get(c); in.get(c);
node->type = node_t::O_GTE; node->type = value_expr_t::O_GTE;
} }
node->left = prev; node->left = prev;
node->right = parse_add_expr(in); node->right = parse_add_expr(in);
@ -654,9 +617,9 @@ node_t * parse_logic_expr(std::istream& in)
return node; return node;
} }
node_t * parse_expr(std::istream& in) value_expr_t * parse_value_expr(std::istream& in)
{ {
node_t * node = NULL; value_expr_t * node = NULL;
node = parse_logic_expr(in); node = parse_logic_expr(in);
@ -666,26 +629,26 @@ node_t * parse_expr(std::istream& in)
in.get(c); in.get(c);
switch (c) { switch (c) {
case '&': { case '&': {
node_t * prev = node; value_expr_t * prev = node;
node = new node_t(node_t::O_AND); node = new value_expr_t(value_expr_t::O_AND);
node->left = prev; node->left = prev;
node->right = parse_logic_expr(in); node->right = parse_logic_expr(in);
break; break;
} }
case '|': { case '|': {
node_t * prev = node; value_expr_t * prev = node;
node = new node_t(node_t::O_OR); node = new value_expr_t(value_expr_t::O_OR);
node->left = prev; node->left = prev;
node->right = parse_logic_expr(in); node->right = parse_logic_expr(in);
break; break;
} }
case '?': { case '?': {
node_t * prev = node; value_expr_t * prev = node;
node = new node_t(node_t::O_QUES); node = new value_expr_t(value_expr_t::O_QUES);
node->left = prev; node->left = prev;
node_t * choices = new node_t(node_t::O_COL); value_expr_t * choices = new value_expr_t(value_expr_t::O_COL);
node->right = choices; node->right = choices;
choices->left = parse_logic_expr(in); choices->left = parse_logic_expr(in);
c = peek_next_nonws(in); c = peek_next_nonws(in);
@ -756,128 +719,128 @@ std::string regexps_to_predicate(std::list<std::string>::const_iterator begin,
#ifdef DEBUG_ENABLED #ifdef DEBUG_ENABLED
void dump_tree(std::ostream& out, const node_t * node) void dump_value_expr(std::ostream& out, const value_expr_t * node)
{ {
switch (node->type) { switch (node->type) {
case node_t::CONSTANT_A: case value_expr_t::CONSTANT_A:
out << "CONST[" << node->constant_a << "]"; out << "CONST[" << node->constant_a << "]";
break; break;
case node_t::CONSTANT_T: case value_expr_t::CONSTANT_T:
out << "DATE/TIME[" << node->constant_t << "]"; out << "DATE/TIME[" << node->constant_t << "]";
break; break;
case node_t::AMOUNT: out << "AMOUNT"; break; case value_expr_t::AMOUNT: out << "AMOUNT"; break;
case node_t::COST: out << "COST"; break; case value_expr_t::COST: out << "COST"; break;
case node_t::DATE: out << "DATE"; break; case value_expr_t::DATE: out << "DATE"; break;
case node_t::CLEARED: out << "CLEARED"; break; case value_expr_t::CLEARED: out << "CLEARED"; break;
case node_t::REAL: out << "REAL"; break; case value_expr_t::REAL: out << "REAL"; break;
case node_t::INDEX: out << "INDEX"; break; case value_expr_t::INDEX: out << "INDEX"; break;
case node_t::BALANCE: out << "BALANCE"; break; case value_expr_t::BALANCE: out << "BALANCE"; break;
case node_t::COST_BALANCE: out << "COST_BALANCE"; break; case value_expr_t::COST_BALANCE: out << "COST_BALANCE"; break;
case node_t::TOTAL: out << "TOTAL"; break; case value_expr_t::TOTAL: out << "TOTAL"; break;
case node_t::COST_TOTAL: out << "COST_TOTAL"; break; case value_expr_t::COST_TOTAL: out << "COST_TOTAL"; break;
case node_t::F_ARITH_MEAN: case value_expr_t::F_ARITH_MEAN:
out << "MEAN("; out << "MEAN(";
dump_tree(out, node->left); dump_value_expr(out, node->left);
out << ")"; out << ")";
break; break;
case node_t::F_NEG: case value_expr_t::F_NEG:
out << "ABS("; out << "ABS(";
dump_tree(out, node->left); dump_value_expr(out, node->left);
out << ")"; out << ")";
break; break;
case node_t::F_ABS: case value_expr_t::F_ABS:
out << "ABS("; out << "ABS(";
dump_tree(out, node->left); dump_value_expr(out, node->left);
out << ")"; out << ")";
break; break;
case node_t::F_PAYEE_MASK: case value_expr_t::F_PAYEE_MASK:
assert(node->mask); assert(node->mask);
out << "P_MASK(" << node->mask->pattern << ")"; out << "P_MASK(" << node->mask->pattern << ")";
break; break;
case node_t::F_ACCOUNT_MASK: case value_expr_t::F_ACCOUNT_MASK:
assert(node->mask); assert(node->mask);
out << "A_MASK(" << node->mask->pattern << ")"; out << "A_MASK(" << node->mask->pattern << ")";
break; break;
case node_t::F_VALUE: case value_expr_t::F_VALUE:
out << "VALUE("; out << "VALUE(";
dump_tree(out, node->left); dump_value_expr(out, node->left);
if (node->right) { if (node->right) {
out << ", "; out << ", ";
dump_tree(out, node->right); dump_value_expr(out, node->right);
} }
out << ")"; out << ")";
break; break;
case node_t::O_NOT: case value_expr_t::O_NOT:
out << "!"; out << "!";
dump_tree(out, node->left); dump_value_expr(out, node->left);
break; break;
case node_t::O_QUES: case value_expr_t::O_QUES:
dump_tree(out, node->left); dump_value_expr(out, node->left);
out << "?"; out << "?";
dump_tree(out, node->right->left); dump_value_expr(out, node->right->left);
out << ":"; out << ":";
dump_tree(out, node->right->right); dump_value_expr(out, node->right->right);
break; break;
case node_t::O_AND: case value_expr_t::O_AND:
case node_t::O_OR: case value_expr_t::O_OR:
out << "("; out << "(";
dump_tree(out, node->left); dump_value_expr(out, node->left);
switch (node->type) { switch (node->type) {
case node_t::O_AND: out << " & "; break; case value_expr_t::O_AND: out << " & "; break;
case node_t::O_OR: out << " | "; break; case value_expr_t::O_OR: out << " | "; break;
default: assert(0); break; default: assert(0); break;
} }
dump_tree(out, node->right); dump_value_expr(out, node->right);
out << ")"; out << ")";
break; break;
case node_t::O_EQ: case value_expr_t::O_EQ:
case node_t::O_LT: case value_expr_t::O_LT:
case node_t::O_LTE: case value_expr_t::O_LTE:
case node_t::O_GT: case value_expr_t::O_GT:
case node_t::O_GTE: case value_expr_t::O_GTE:
out << "("; out << "(";
dump_tree(out, node->left); dump_value_expr(out, node->left);
switch (node->type) { switch (node->type) {
case node_t::O_EQ: out << "="; break; case value_expr_t::O_EQ: out << "="; break;
case node_t::O_LT: out << "<"; break; case value_expr_t::O_LT: out << "<"; break;
case node_t::O_LTE: out << "<="; break; case value_expr_t::O_LTE: out << "<="; break;
case node_t::O_GT: out << ">"; break; case value_expr_t::O_GT: out << ">"; break;
case node_t::O_GTE: out << ">="; break; case value_expr_t::O_GTE: out << ">="; break;
default: assert(0); break; default: assert(0); break;
} }
dump_tree(out, node->right); dump_value_expr(out, node->right);
out << ")"; out << ")";
break; break;
case node_t::O_ADD: case value_expr_t::O_ADD:
case node_t::O_SUB: case value_expr_t::O_SUB:
case node_t::O_MUL: case value_expr_t::O_MUL:
case node_t::O_DIV: case value_expr_t::O_DIV:
out << "("; out << "(";
dump_tree(out, node->left); dump_value_expr(out, node->left);
switch (node->type) { switch (node->type) {
case node_t::O_ADD: out << "+"; break; case value_expr_t::O_ADD: out << "+"; break;
case node_t::O_SUB: out << "-"; break; case value_expr_t::O_SUB: out << "-"; break;
case node_t::O_MUL: out << "*"; break; case value_expr_t::O_MUL: out << "*"; break;
case node_t::O_DIV: out << "/"; break; case value_expr_t::O_DIV: out << "/"; break;
default: assert(0); break; default: assert(0); break;
} }
dump_tree(out, node->right); dump_value_expr(out, node->right);
out << ")"; out << ")";
break; break;
case node_t::LAST: case value_expr_t::LAST:
default: default:
assert(0); assert(0);
break; break;
@ -892,7 +855,7 @@ void dump_tree(std::ostream& out, const node_t * node)
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
ledger::dump_tree(std::cout, ledger::parse_expr(argv[1])); ledger::dump_value_exp(std::cout, ledger::parse_value_expr(argv[1]));
std::cout << std::endl; std::cout << std::endl;
} }

View file

@ -20,13 +20,6 @@ class mask_t
bool match(const std::string& str) const; bool match(const std::string& str) const;
}; };
#if 1
typedef std::list<mask_t> masks_list;
bool matches(const masks_list& regexps, const std::string& str,
bool * by_exclusion = NULL);
#endif
struct details_t struct details_t
{ {
@ -44,7 +37,7 @@ struct details_t
: entry(NULL), xact(NULL), account(_account) {} : entry(NULL), xact(NULL), account(_account) {}
}; };
struct node_t struct value_expr_t
{ {
enum kind_t { enum kind_t {
// Constants // Constants
@ -92,18 +85,18 @@ struct node_t
LAST LAST
}; };
kind_t type; kind_t type;
node_t * left; value_expr_t * left;
node_t * right; value_expr_t * right;
amount_t constant_a; amount_t constant_a;
std::time_t constant_t; std::time_t constant_t;
mask_t * mask; mask_t * mask;
node_t(const kind_t _type) value_expr_t(const kind_t _type)
: type(_type), left(NULL), right(NULL), mask(NULL) {} : type(_type), left(NULL), right(NULL), mask(NULL) {}
~node_t() { ~value_expr_t() {
if (mask) delete mask; if (mask) delete mask;
if (left) delete left; if (left) delete left;
if (right) delete right; if (right) delete right;
@ -112,52 +105,42 @@ struct node_t
void compute(balance_t& result, const details_t& details) const; void compute(balance_t& result, const details_t& details) const;
}; };
node_t * parse_expr(std::istream& in); value_expr_t * parse_value_expr(std::istream& in);
inline node_t * parse_expr(const char * p) { inline value_expr_t * parse_value_expr(const char * p) {
std::istringstream stream(p); std::istringstream stream(p);
return parse_expr(stream); return parse_value_expr(stream);
} }
inline node_t * parse_expr(const std::string& str) { inline value_expr_t * parse_value_expr(const std::string& str) {
return parse_expr(str.c_str()); return parse_value_expr(str.c_str());
}
inline node_t * find_node(node_t * node, node_t::kind_t type) {
node_t * result = NULL;
if (node->type == type)
result = node;
if (! result && node->left)
result = find_node(node->left, type);
if (! result && node->right)
result = find_node(node->right, type);
return result;
} }
#ifdef DEBUG_ENABLED #ifdef DEBUG_ENABLED
void dump_tree(std::ostream& out, const node_t * node); void dump_value_expr(std::ostream& out, const value_expr_t * node);
#endif #endif
template <typename T> template <typename T>
class item_predicate class item_predicate
{ {
const node_t * predicate; const value_expr_t * predicate;
public: public:
item_predicate(const std::string& _predicate) item_predicate(const std::string& _predicate)
: predicate(_predicate.empty() ? NULL : parse_expr(_predicate)) { : predicate(_predicate.empty() ?
NULL : parse_value_expr(_predicate)) {
#ifdef DEBUG_ENABLED #ifdef DEBUG_ENABLED
DEBUG_CLASS("valexpr.predicate.parse"); DEBUG_CLASS("valexpr.predicate.parse");
DEBUG_PRINT_("parsing: '" << _predicate << "'"); DEBUG_PRINT_("parsing: '" << _predicate << "'");
if (DEBUG_() && ledger::debug_stream) { if (DEBUG_() && ledger::debug_stream) {
*ledger::debug_stream << "dump: "; *ledger::debug_stream << "dump: ";
dump_tree(*ledger::debug_stream, predicate); dump_value_expr(*ledger::debug_stream, predicate);
*ledger::debug_stream << std::endl; *ledger::debug_stream << std::endl;
} }
#endif #endif
} }
item_predicate(const node_t * _predicate) item_predicate(const value_expr_t * _predicate)
: predicate(_predicate) {} : predicate(_predicate) {}
~item_predicate() { ~item_predicate() {

87
walk.cc
View file

@ -30,30 +30,29 @@ void collapse_transactions::report_cumulative_subtotal()
{ {
if (count == 1) { if (count == 1) {
(*handler)(last_xact); (*handler)(last_xact);
return; } else {
assert(count > 1);
totals_account->total = subtotal;
balance_t result;
format_t::compute_total(result, details_t(totals_account));
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);
xact_temps.push_back(total_xact);
total_xact->amount = (*i).second;
total_xact->cost = (*i).second;
(*handler)(total_xact);
}
} }
assert(count > 1); subtotal = 0;
count = 0;
transaction_t * total_xact = new transaction_t(NULL, totals_account);
balance_t value;
total_xact->total = subtotal;
format_t::compute_total(value, details_t(total_xact));
total_xact->total = 0;
total_xact->entry = last_entry;
for (amounts_map::const_iterator i = value.amounts.begin();
i != value.amounts.end();
i++) {
total_xact->amount = (*i).second;
total_xact->cost = (*i).second;
(*handler)(total_xact);
}
xact_temps.push_back(total_xact);
} }
void changed_value_transactions::operator()(transaction_t * xact) void changed_value_transactions::operator()(transaction_t * xact)
@ -82,13 +81,12 @@ void changed_value_transactions::operator()(transaction_t * xact)
i != diff.amounts.end(); i != diff.amounts.end();
i++) { i++) {
transaction_t * temp_xact = new transaction_t(entry, NULL); transaction_t * temp_xact = new transaction_t(entry, NULL);
xact_temps.push_back(temp_xact);
temp_xact->amount = (*i).second; temp_xact->amount = (*i).second;
temp_xact->total = (*i).second; temp_xact->total = (*i).second;
temp_xact->total.negate(); temp_xact->total.negate();
xact_temps.push_back(temp_xact);
(*handler)(temp_xact); (*handler)(temp_xact);
} }
} }
@ -115,19 +113,21 @@ void subtotal_transactions::flush()
i != balances.end(); i != balances.end();
i++) { i++) {
entry->date = finish; entry->date = finish;
transaction_t * xact = new transaction_t(entry, (*i).first); transaction_t temp(entry, (*i).first);
xact->total = (*i).second; temp.total = (*i).second;
balance_t result; balance_t result;
format_t::compute_total(result, details_t(xact)); format_t::compute_total(result, details_t(&temp));
xact->total = 0;
entry->date = start; entry->date = start;
xact_temps.push_back(xact);
for (amounts_map::const_iterator j = result.amounts.begin(); for (amounts_map::const_iterator j = result.amounts.begin();
j != result.amounts.end(); j != result.amounts.end();
j++) { j++) {
xact->amount = xact->cost = (*j).second; transaction_t * xact = new transaction_t(entry, (*i).first);
xact_temps.push_back(xact);
xact->amount = (*j).second;
xact->cost = (*j).second;
(*handler)(xact); (*handler)(xact);
} }
} }
@ -153,29 +153,4 @@ void subtotal_transactions::operator()(transaction_t * xact)
(*i).second += *xact; (*i).second += *xact;
} }
struct sum_in_account : public item_handler<transaction_t>
{
virtual void operator()(transaction_t * xact) {
xact->account->value += *xact;
}
};
void calc__accounts(account_t * account,
const item_predicate<transaction_t>& pred,
unsigned int flags)
{
sum_in_account handler;
for (transactions_list::iterator i = account->transactions.begin();
i != account->transactions.end();
i++)
if (pred(*i))
handle_transaction(*i, handler, flags);
for (accounts_map::iterator i = account->accounts.begin();
i != account->accounts.end();
i++)
calc__accounts((*i).second, pred, flags);
}
} // namespace ledger } // namespace ledger

312
walk.h
View file

@ -20,9 +20,9 @@ struct item_handler {
template <typename T> template <typename T>
struct compare_items { struct compare_items {
const node_t * sort_order; const value_expr_t * sort_order;
compare_items(const node_t * _sort_order) compare_items(const value_expr_t * _sort_order)
: sort_order(_sort_order) { : sort_order(_sort_order) {
assert(sort_order); assert(sort_order);
} }
@ -40,27 +40,34 @@ struct compare_items {
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
// //
// Several default handlers // Transaction handlers
// //
typedef std::deque<transaction_t *> transactions_deque; typedef std::deque<transaction_t *> transactions_deque;
typedef std::deque<entry_t *> entries_deque; typedef std::deque<entry_t *> entries_deque;
struct ignore_transaction : public item_handler<transaction_t> struct ignore_transactions : public item_handler<transaction_t>
{ {
virtual void operator()(transaction_t * xact) {} virtual void operator()(transaction_t * xact) {}
}; };
struct clear_display_flags : public item_handler<transaction_t>
{
virtual void operator()(transaction_t * xact) {
xact->dflags = 0;
}
};
class sort_transactions : public item_handler<transaction_t> class sort_transactions : public item_handler<transaction_t>
{ {
transactions_deque transactions; transactions_deque transactions;
const node_t * sort_order; const value_expr_t * sort_order;
item_handler<transaction_t> * handler; item_handler<transaction_t> * handler;
public: public:
sort_transactions(item_handler<transaction_t> * _handler, sort_transactions(item_handler<transaction_t> * _handler,
const node_t * _sort_order) const value_expr_t * _sort_order)
: sort_order(_sort_order), handler(_handler) {} : sort_order(_sort_order), handler(_handler) {}
virtual ~sort_transactions() { virtual ~sort_transactions() {
@ -173,11 +180,8 @@ class collapse_transactions : public item_handler<transaction_t>
// If we've reached a new entry, report on the subtotal // If we've reached a new entry, report on the subtotal
// accumulated thus far. // accumulated thus far.
if (last_entry && last_entry != xact->entry) { if (last_entry && last_entry != xact->entry)
report_cumulative_subtotal(); report_cumulative_subtotal();
subtotal = 0;
count = 0;
}
subtotal += *xact; subtotal += *xact;
count++; count++;
@ -302,90 +306,175 @@ class interval_transactions : public subtotal_transactions
} }
}; };
////////////////////////////////////////////////////////////////////// class related_transactions : public item_handler<transaction_t>
#define MATCHING_TRANSACTIONS 0x01
#define OTHER_TRANSACTIONS 0x02
inline void handle_transaction(transaction_t * xact,
item_handler<transaction_t>& handler,
unsigned int flags)
{ {
for (transactions_list::iterator i = xact->entry->transactions.begin(); bool also_matching;
i != xact->entry->transactions.end();
i++)
if ((! (flags & OTHER_TRANSACTIONS) ||
! ((*i)->flags & TRANSACTION_AUTO)) &&
! ((*i)->dflags & TRANSACTION_HANDLED) &&
(*i == xact ?
(flags & MATCHING_TRANSACTIONS) : (flags & OTHER_TRANSACTIONS))) {
(*i)->dflags |= TRANSACTION_HANDLED;
handler(*i);
}
}
inline void walk_entries(entries_list::iterator begin, item_handler<transaction_t> * handler;
entries_list::iterator end,
item_handler<transaction_t>& handler,
const std::string& predicate,
unsigned int flags)
{
item_predicate<transaction_t> pred(predicate);
for (entries_list::iterator i = begin; i != end; i++) public:
for (transactions_list::iterator j = (*i)->transactions.begin(); related_transactions(item_handler<transaction_t> * _handler,
j != (*i)->transactions.end(); bool _also_matching = false)
j++) : also_matching(_also_matching), handler(_handler) {}
if (pred(*j))
handle_transaction(*j, handler, flags);
}
inline void walk_entries(entries_list::iterator begin, virtual ~related_transactions() {
entries_list::iterator end, handler->flush();
item_handler<transaction_t>& handler) delete handler;
{ }
for (entries_list::iterator i = begin; i != end; i++)
for (transactions_list::iterator j = (*i)->transactions.begin();
j != (*i)->transactions.end();
j++)
handler(*j);
}
struct clear_flags : public item_handler<transaction_t>
{
virtual void operator()(transaction_t * xact) { virtual void operator()(transaction_t * xact) {
xact->dflags = 0; for (transactions_list::iterator i = xact->entry->transactions.begin();
i != xact->entry->transactions.end();
i++)
if (! ((*i)->dflags & TRANSACTION_HANDLED) &&
(*i == xact ? also_matching :
! ((*i)->flags & TRANSACTION_AUTO))) {
(*i)->dflags |= TRANSACTION_HANDLED;
(*handler)(*i);
}
} }
}; };
inline void clear_transaction_display_flags(entries_list::iterator begin, //////////////////////////////////////////////////////////////////////
entries_list::iterator end)
{
clear_flags handler;
walk_entries(begin, end, handler);
}
inline void walk_transactions(transactions_list::iterator begin, inline void walk_transactions(transactions_list::iterator begin,
transactions_list::iterator end, transactions_list::iterator end,
item_handler<transaction_t>& handler) item_handler<transaction_t>& handler) {
{
for (transactions_list::iterator i = begin; i != end; i++) for (transactions_list::iterator i = begin; i != end; i++)
handler(*i); handler(*i);
} }
inline void walk_transactions(transactions_list& list,
item_handler<transaction_t>& handler) {
walk_transactions(list.begin(), list.end(), handler);
}
inline void walk_transactions(transactions_deque::iterator begin, inline void walk_transactions(transactions_deque::iterator begin,
transactions_deque::iterator end, transactions_deque::iterator end,
item_handler<transaction_t>& handler) item_handler<transaction_t>& handler) {
{
for (transactions_deque::iterator i = begin; i != end; i++) for (transactions_deque::iterator i = begin; i != end; i++)
handler(*i); handler(*i);
} }
inline void walk_transactions(transactions_deque& deque,
item_handler<transaction_t>& handler) {
walk_transactions(deque.begin(), deque.end(), handler);
}
inline void walk_entries(entries_list::iterator begin,
entries_list::iterator end,
item_handler<transaction_t>& handler) {
// jww (2004-08-11): do transaction dflags need to be cleared first?
for (entries_list::iterator i = begin; i != end; i++)
walk_transactions((*i)->transactions, handler);
}
inline void walk_entries(entries_list& list,
item_handler<transaction_t>& handler) {
walk_entries(list.begin(), list.end(), handler);
}
//////////////////////////////////////////////////////////////////////
//
// Account handlers
//
typedef std::deque<account_t *> accounts_deque; typedef std::deque<account_t *> accounts_deque;
struct add_to_account_value : public item_handler<transaction_t>
{
virtual void operator()(transaction_t * xact) {
xact->account->value += *xact;
}
};
#if 0
class format_accounts : public item_handler<account_t>
{
};
class filter_accounts : public item_handler<account_t>
{
item_handler<account_t> * handler;
public:
filter_accounts(item_handler<account_t> * _handler)
: handler(_handler) {}
virtual ~filter_accounts() {
handler->flush();
delete handler;
}
virtual void flush() {}
virtual void operator()(account_t * account) {
}
};
class sort_accounts : public item_handler<account_t>
{
value_expr_t * sort_order;
item_handler<account_t> * handler;
public:
sort_accounts(item_handler<account_t> * _handler,
value_expr_t * _sort_order)
: sort_order(_sort_order), handler(_handler) {}
virtual ~sort_accounts() {
handler->flush();
delete handler;
}
virtual void flush() {}
virtual void operator()(account_t * account) {
accounts_deque accounts;
for (accounts_map::iterator i = account->accounts.begin();
i != account->accounts.end();
i++)
accounts.push_back((*i).second);
std::stable_sort(accounts.begin(), accounts.end(),
compare_items<account_t>(sort_order));
}
};
class balance_accounts : public item_handler<account_t>
{
item_handler<account_t> * handler;
public:
balance_accounts(item_handler<account_t> * _handler)
: handler(_handler) {}
virtual ~balance_accounts() {
handler->flush();
delete handler;
}
virtual void flush() {
if (format_account::disp_subaccounts_p(top)) {
std::string end_format = "--------------------\n";
format.reset(end_format + f);
format.format_elements(std::cout, details_t(top));
}
}
virtual void operator()(account_t * account) {
}
};
#endif
inline void sort_accounts(account_t * account, inline void sort_accounts(account_t * account,
accounts_deque& accounts, accounts_deque& accounts,
const node_t * sort_order) const value_expr_t * sort_order)
{ {
for (accounts_map::iterator i = account->accounts.begin(); for (accounts_map::iterator i = account->accounts.begin();
i != account->accounts.end(); i != account->accounts.end();
@ -396,6 +485,32 @@ inline void sort_accounts(account_t * account,
compare_items<account_t>(sort_order)); compare_items<account_t>(sort_order));
} }
inline void walk__accounts_sorted(account_t * account,
item_handler<account_t>& handler,
const value_expr_t * sort_order)
{
handler(account);
accounts_deque accounts;
sort_accounts(account, accounts, sort_order);
for (accounts_deque::const_iterator i = accounts.begin();
i != accounts.end();
i++)
walk__accounts_sorted(*i, handler, sort_order);
}
inline void sum__accounts(account_t * account)
{
for (accounts_map::iterator i = account->accounts.begin();
i != account->accounts.end();
i++) {
sum__accounts((*i).second);
account->total += (*i).second->total;
}
account->total += account->value;
}
inline void walk__accounts(account_t * account, inline void walk__accounts(account_t * account,
item_handler<account_t>& handler) item_handler<account_t>& handler)
{ {
@ -407,64 +522,11 @@ inline void walk__accounts(account_t * account,
walk__accounts((*i).second, handler); walk__accounts((*i).second, handler);
} }
inline void walk__accounts_sorted(account_t * account, inline void walk_accounts(account_t * account,
item_handler<account_t>& handler, item_handler<account_t>& handler,
const node_t * sort_order) const bool calc_subtotals,
const value_expr_t * sort_order = NULL)
{ {
handler(account);
accounts_deque accounts;
for (accounts_map::const_iterator i = account->accounts.begin();
i != account->accounts.end();
i++)
accounts.push_back((*i).second);
std::stable_sort(accounts.begin(), accounts.end(),
compare_items<account_t>(sort_order));
for (accounts_deque::const_iterator i = accounts.begin();
i != accounts.end();
i++)
walk__accounts_sorted(*i, handler, sort_order);
}
inline void for_each_account(account_t * account,
item_handler<account_t>& handler)
{
handler(account);
for (accounts_map::iterator i = account->accounts.begin();
i != account->accounts.end();
i++)
walk__accounts((*i).second, handler);
}
void calc__accounts(account_t * account,
const item_predicate<transaction_t>& pred,
unsigned int flags);
inline void sum__accounts(account_t * account)
{
for (accounts_map::iterator i = account->accounts.begin();
i != account->accounts.end();
i++) {
sum__accounts((*i).second);
account->total += (*i).second->total;
}
account->total += account->value;
}
inline void walk_accounts(account_t * account,
item_handler<account_t>& handler,
const std::string& predicate,
unsigned int flags,
const bool calc_subtotals,
const node_t * sort_order = NULL)
{
item_predicate<transaction_t> pred(predicate);
calc__accounts(account, pred, flags);
if (calc_subtotals) if (calc_subtotals)
sum__accounts(account); sum__accounts(account);