new debug code; automated transactions now use value expression predicates

This commit is contained in:
John Wiegley 2004-08-10 17:54:47 -04:00
parent 799e97e420
commit 7a1d0d4614
15 changed files with 273 additions and 253 deletions

View file

@ -4,6 +4,7 @@ CODE = account.cc \
balance.cc \
binary.cc \
datetime.cc \
debug.cc \
error.cc \
format.cc \
ledger.cc \
@ -17,9 +18,9 @@ OBJS = $(patsubst %.cc,%.o,$(CODE))
CXX = g++
CFLAGS = -Wall -ansi -pedantic
#DFLAGS = -O3 -fomit-frame-pointer
DFLAGS = -g -DDEBUG=1
#DFLAGS = -g -DDEBUG=1 -pg
#DFLAGS = -O3 -fomit-frame-pointer -DRELEASE_LEVEL=0
DFLAGS = -g -DRELEASE_LEVEL=4
#DFLAGS = -g -DRELEASE_LEVEL=2 -pg
INCS = -I/sw/include \
-I/usr/include/gcc/darwin/3.3/c++ \

12
NEWS
View file

@ -54,7 +54,7 @@
-W Report the trend, with older values affecting the trend less
-X Report expected amount for the next transaction
- Amount expressions are now supported, where the totals reported can
- Value expressions are now supported, where the totals reported can
be changed using -t and -T and an expression string composed of:
a amount
@ -142,6 +142,16 @@
%?10d %?-.20p %-.22a %12.66t %12.80T
%20T %-a
- Automated transactions now use a single value expression as a
predicate. This means the new syntax is:
= VALUE-EXPR
TRANSACTIONS...
Only one VALUE-EXPR is supported, compared to the multiple account
regexps supported before. By using a VALUE-EXPR as a predicate,
matching may now be much more comprehensive and selective.
* 1.7 (never released)
- Pricing histories are now supported, so that ledger remembers

View file

@ -4,11 +4,14 @@ namespace ledger {
void automated_transaction_t::extend_entry(entry_t * entry)
{
for (transactions_list::iterator i = entry->transactions.begin();
i != entry->transactions.end();
transactions_deque initial_xacts(entry->transactions.begin(),
entry->transactions.end());
for (transactions_deque::iterator i = initial_xacts.begin();
i != initial_xacts.end();
i++)
if (matches(masks, *((*i)->account))) {
for (transactions_list::iterator t = transactions.begin();
if (predicate(*i))
for (transactions_deque::iterator t = transactions.begin();
t != transactions.end();
t++) {
amount_t amt;
@ -22,7 +25,6 @@ void automated_transaction_t::extend_entry(entry_t * entry)
(*t)->flags | TRANSACTION_AUTO);
entry->add_transaction(xact);
}
}
}
} // namespace ledger

View file

@ -8,15 +8,17 @@
namespace ledger {
typedef std::deque<transaction_t *> transactions_deque;
class automated_transaction_t
{
public:
masks_list masks;
transactions_list transactions;
item_predicate<transaction_t> predicate;
transactions_deque transactions;
automated_transaction_t(masks_list& _masks,
transactions_list& _transactions) {
masks.insert(masks.begin(), _masks.begin(), _masks.end());
automated_transaction_t(const std::string& _predicate,
transactions_deque& _transactions)
: predicate(_predicate) {
transactions.insert(transactions.begin(),
_transactions.begin(), _transactions.end());
// Take over ownership of the pointers
@ -24,7 +26,7 @@ public:
}
~automated_transaction_t() {
for (transactions_list::iterator i = transactions.begin();
for (transactions_deque::iterator i = transactions.begin();
i != transactions.end();
i++)
delete *i;

View file

@ -352,7 +352,7 @@ inline balance_t abs(const balance_t& bal) {
return temp;
}
#ifdef DEBUG
#ifdef DEBUG_ENABLED
inline std::ostream& operator<<(std::ostream& out, const balance_t& bal) {
bal.write(out, 12);
return out;

View file

@ -29,7 +29,7 @@ void read_binary_amount(std::istream& in, amount_t& amt)
{
unsigned long id;
#ifdef DEBUG
#ifdef DEBUG_ENABLED
{
unsigned short guard;
in.read((char *)&guard, sizeof(guard));
@ -45,7 +45,7 @@ void read_binary_amount(std::istream& in, amount_t& amt)
amt.read_quantity(in);
#ifdef DEBUG
#ifdef DEBUG_ENABLED
{
unsigned short guard;
in.read((char *)&guard, sizeof(guard));
@ -60,7 +60,7 @@ transaction_t * read_binary_transaction(std::istream& in, entry_t * entry)
unsigned long id;
#ifdef DEBUG
#ifdef DEBUG_ENABLED
{
unsigned short guard;
in.read((char *)&guard, sizeof(guard));
@ -85,7 +85,7 @@ transaction_t * read_binary_transaction(std::istream& in, entry_t * entry)
xact->note = buf;
}
#ifdef DEBUG
#ifdef DEBUG_ENABLED
{
unsigned short guard;
in.read((char *)&guard, sizeof(guard));
@ -100,7 +100,7 @@ entry_t * read_binary_entry(std::istream& in, journal_t * journal)
{
entry_t * entry = new entry_t;
#ifdef DEBUG
#ifdef DEBUG_ENABLED
{
unsigned short guard;
in.read((char *)&guard, sizeof(guard));
@ -134,7 +134,7 @@ entry_t * read_binary_entry(std::istream& in, journal_t * journal)
entry->transactions.push_back(xact);
}
#ifdef DEBUG
#ifdef DEBUG_ENABLED
{
unsigned short guard;
in.read((char *)&guard, sizeof(guard));
@ -152,7 +152,7 @@ commodity_t * read_binary_commodity(std::istream& in)
commodity_t * commodity = new commodity_t;
commodities.push_back(commodity);
#ifdef DEBUG
#ifdef DEBUG_ENABLED
{
unsigned short guard;
in.read((char *)&guard, sizeof(guard));
@ -202,7 +202,7 @@ commodity_t * read_binary_commodity(std::istream& in)
read_binary_amount(in, commodity->conversion);
#ifdef DEBUG
#ifdef DEBUG_ENABLED
{
unsigned short guard;
in.read((char *)&guard, sizeof(guard));
@ -220,7 +220,7 @@ account_t * read_binary_account(std::istream& in, account_t * master = NULL)
account_t * acct = new account_t(NULL);
accounts.push_back(acct);
#ifdef DEBUG
#ifdef DEBUG_ENABLED
{
unsigned short guard;
in.read((char *)&guard, sizeof(guard));
@ -272,7 +272,7 @@ account_t * read_binary_account(std::istream& in, account_t * master = NULL)
acct->add_account(child);
}
#ifdef DEBUG
#ifdef DEBUG_ENABLED
{
unsigned short guard;
in.read((char *)&guard, sizeof(guard));
@ -296,7 +296,7 @@ unsigned int read_binary_journal(std::istream& in,
if (magic != binary_magic_number)
return 0;
#ifdef DEBUG
#ifdef DEBUG_ENABLED
{
unsigned short guard;
in.read((char *)&guard, sizeof(guard));
@ -356,7 +356,7 @@ unsigned int read_binary_journal(std::istream& in,
journal->entries.push_back(entry);
}
#ifdef DEBUG
#ifdef DEBUG_ENABLED
{
unsigned short guard;
in.read((char *)&guard, sizeof(guard));
@ -373,7 +373,7 @@ unsigned int read_binary_journal(std::istream& in,
void write_binary_amount(std::ostream& out, const amount_t& amt)
{
#ifdef DEBUG
#ifdef DEBUG_ENABLED
{
unsigned short guard = 0x1001;
out.write((char *)&guard, sizeof(guard));
@ -389,7 +389,7 @@ void write_binary_amount(std::ostream& out, const amount_t& amt)
amt.write_quantity(out);
#ifdef DEBUG
#ifdef DEBUG_ENABLED
{
unsigned short guard = 0x1002;
out.write((char *)&guard, sizeof(guard));
@ -399,7 +399,7 @@ void write_binary_amount(std::ostream& out, const amount_t& amt)
void write_binary_transaction(std::ostream& out, transaction_t * xact)
{
#ifdef DEBUG
#ifdef DEBUG_ENABLED
{
unsigned short guard = 0x1003;
out.write((char *)&guard, sizeof(guard));
@ -416,7 +416,7 @@ void write_binary_transaction(std::ostream& out, transaction_t * xact)
if (len)
out.write(xact->note.c_str(), len);
#ifdef DEBUG
#ifdef DEBUG_ENABLED
{
unsigned short guard = 0x1004;
out.write((char *)&guard, sizeof(guard));
@ -426,7 +426,7 @@ void write_binary_transaction(std::ostream& out, transaction_t * xact)
void write_binary_entry(std::ostream& out, entry_t * entry)
{
#ifdef DEBUG
#ifdef DEBUG_ENABLED
{
unsigned short guard = 0x1005;
out.write((char *)&guard, sizeof(guard));
@ -454,7 +454,7 @@ void write_binary_entry(std::ostream& out, entry_t * entry)
i++)
write_binary_transaction(out, *i);
#ifdef DEBUG
#ifdef DEBUG_ENABLED
{
unsigned short guard = 0x1006;
out.write((char *)&guard, sizeof(guard));
@ -464,7 +464,7 @@ void write_binary_entry(std::ostream& out, entry_t * entry)
void write_binary_commodity(std::ostream& out, commodity_t * commodity)
{
#ifdef DEBUG
#ifdef DEBUG_ENABLED
{
unsigned short guard = 0x1007;
out.write((char *)&guard, sizeof(guard));
@ -504,7 +504,7 @@ void write_binary_commodity(std::ostream& out, commodity_t * commodity)
write_binary_amount(out, commodity->conversion);
#ifdef DEBUG
#ifdef DEBUG_ENABLED
{
unsigned short guard = 0x1008;
out.write((char *)&guard, sizeof(guard));
@ -514,7 +514,7 @@ void write_binary_commodity(std::ostream& out, commodity_t * commodity)
void write_binary_account(std::ostream& out, account_t * account)
{
#ifdef DEBUG
#ifdef DEBUG_ENABLED
{
unsigned short guard = 0x1009;
out.write((char *)&guard, sizeof(guard));
@ -552,7 +552,7 @@ void write_binary_account(std::ostream& out, account_t * account)
i++)
write_binary_account(out, (*i).second);
#ifdef DEBUG
#ifdef DEBUG_ENABLED
{
unsigned short guard = 0x1010;
out.write((char *)&guard, sizeof(guard));
@ -565,7 +565,7 @@ void write_binary_journal(std::ostream& out, journal_t * journal,
{
out.write((char *)&binary_magic_number, sizeof(binary_magic_number));
#ifdef DEBUG
#ifdef DEBUG_ENABLED
{
unsigned short guard = 0x1011;
out.write((char *)&guard, sizeof(guard));
@ -613,7 +613,7 @@ void write_binary_journal(std::ostream& out, journal_t * journal,
i++)
write_binary_entry(out, *i);
#ifdef DEBUG
#ifdef DEBUG_ENABLED
{
unsigned short guard = 0x1012;
out.write((char *)&guard, sizeof(guard));

View file

@ -6,15 +6,6 @@
#include <exception>
#include <string>
#ifdef DEBUG
#include <cassert>
#else
#ifdef assert
#undef assert
#endif
#define assert(x)
#endif
namespace ledger {
class error : public std::exception

View file

@ -104,14 +104,14 @@ class format_transaction
mutable transaction_t * last_xact;
public:
format_transaction(std::ostream& _output_stream,
const format_t& _first_line_format,
const format_t& _next_lines_format,
const node_t * display_predicate = NULL,
format_transaction(std::ostream& _output_stream,
const format_t& _first_line_format,
const format_t& _next_lines_format,
const std::string& display_predicate = NULL,
#ifdef COLLAPSED_REGISTER
const bool _collapsed = false,
const bool _collapsed = false,
#endif
const bool _inverted = false)
const bool _inverted = false)
: output_stream(_output_stream),
first_line_format(_first_line_format),
next_lines_format(_next_lines_format),
@ -198,9 +198,9 @@ class format_account
item_predicate<account_t> disp_pred_functor;
public:
format_account(std::ostream& _output_stream,
const format_t& _format,
const node_t * display_predicate = NULL)
format_account(std::ostream& _output_stream,
const format_t& _format,
const std::string& display_predicate = NULL)
: output_stream(_output_stream), format(_format),
disp_pred_functor(display_predicate) {}
@ -237,10 +237,10 @@ class format_equity
mutable balance_t total;
public:
format_equity(std::ostream& _output_stream,
const format_t& _first_line_format,
const format_t& _next_lines_format,
const node_t * display_predicate = NULL)
format_equity(std::ostream& _output_stream,
const format_t& _first_line_format,
const format_t& _next_lines_format,
const std::string& display_predicate = NULL)
: output_stream(_output_stream),
first_line_format(_first_line_format),
next_lines_format(_next_lines_format),

View file

@ -19,6 +19,12 @@
#include "amount.h"
#include "balance.h"
#ifdef RELEASE_LEVEL
#if RELEASE_LEVEL >= 2
#include "debug.h"
#endif
#endif
namespace ledger {
#define TRANSACTION_NORMAL 0x00

214
main.cc
View file

@ -102,34 +102,6 @@ void download_price_quote(commodity_t * commodity,
} // namespace ledger
static void assemble_regexp_predicate(std::string& predicate_string,
const std::list<std::string>& strings,
const bool exclude = false,
const bool payee = false)
{
if (strings.size() == 0)
return;
if (! predicate_string.empty())
predicate_string += "&";
if (exclude)
predicate_string += "!";
if (payee)
predicate_string += "/";
predicate_string += "/(";
bool first = true;
for (std::list<std::string>::const_iterator i = strings.begin();
i != strings.end();
i++) {
if (first)
first = false;
else
predicate_string += "|";
predicate_string += *i;
}
predicate_string += ")/";
}
static void show_version(std::ostream& out)
{
out
@ -186,13 +158,11 @@ int main(int argc, char * argv[])
using namespace ledger;
std::auto_ptr<journal_t> journal(new journal_t);
std::list<std::string> files;
std::auto_ptr<node_t> predicate;
std::auto_ptr<node_t> display_predicate;
std::auto_ptr<node_t> sort_order;
std::list<std::string> files;
std::auto_ptr<node_t> sort_order;
std::string predicate_string;
std::string display_predicate_string;
std::string predicate;
std::string display_predicate;
std::string format_string;
std::string sort_string;
std::string value_expr = "a";
@ -207,8 +177,11 @@ int main(int argc, char * argv[])
bool show_commodities_revalued = false;
bool show_commodities_revalued_only = false;
#ifdef DEBUG
bool debug = false;
#ifdef DEBUG_ENABLED
if (char * p = std::getenv("DEBUG_FILE")) {
debug_stream = new std::ofstream(p);
free_debug_stream = true;
}
#endif
// Initialize some variables based on environment variable settings
@ -251,19 +224,13 @@ int main(int argc, char * argv[])
int c, index;
while (-1 !=
(c = getopt(argc, argv,
"+ABb:Ccd:DEe:F:f:Ghi:L:l:MnoOP:p:QRS:st:T:UVvWXZz"))) {
"+ABb:Ccd:DEe:F:f:Ghi:L:l:MnoOP:p:QRS:st:T:UVvWXZ"))) {
switch (char(c)) {
// Basic options
case 'h':
show_help(std::cout);
break;
#ifdef DEBUG
case 'z':
debug = 1;
break;
#endif
case 'v':
show_version(std::cout);
return 0;
@ -278,48 +245,48 @@ int main(int argc, char * argv[])
break;
case 'b':
if (! predicate_string.empty())
predicate_string += "&";
predicate_string += "(d>=[";
predicate_string += optarg;
predicate_string += "])";
if (! predicate.empty())
predicate += "&";
predicate += "(d>=[";
predicate += optarg;
predicate += "])";
break;
case 'e':
if (! predicate_string.empty())
predicate_string += "&";
predicate_string += "(d<[";
predicate_string += optarg;
predicate_string += "])";
if (! predicate.empty())
predicate += "&";
predicate += "(d<[";
predicate += optarg;
predicate += "])";
break;
case 'c': {
if (! predicate_string.empty())
predicate_string += "&";
predicate_string += "(d<";
if (! predicate.empty())
predicate += "&";
predicate += "(d<";
std::ostringstream now;
now << std::time(NULL);
predicate_string += now.str();
predicate_string += ")";
predicate += now.str();
predicate += ")";
break;
}
case 'C':
if (! predicate_string.empty())
predicate_string += "&";
predicate_string += "X";
if (! predicate.empty())
predicate += "&";
predicate += "X";
break;
case 'U':
if (! predicate_string.empty())
predicate_string += "&";
predicate_string += "!X";
if (! predicate.empty())
predicate += "&";
predicate += "!X";
break;
case 'R':
if (! predicate_string.empty())
predicate_string += "&";
predicate_string += "R";
if (! predicate.empty())
predicate += "&";
predicate += "R";
break;
// Customizing output
@ -348,19 +315,19 @@ int main(int argc, char * argv[])
break;
case 'l':
if (! predicate_string.empty())
predicate_string += "&";
predicate_string += "(";
predicate_string += optarg;
predicate_string += ")";
if (! predicate.empty())
predicate += "&";
predicate += "(";
predicate += optarg;
predicate += ")";
break;
case 'd':
if (! display_predicate_string.empty())
display_predicate_string += "&";
display_predicate_string += "(";
display_predicate_string += optarg;
display_predicate_string += ")";
if (! display_predicate.empty())
display_predicate += "&";
display_predicate += "(";
display_predicate += optarg;
display_predicate += ")";
break;
// Commodity reporting
@ -518,81 +485,56 @@ int main(int argc, char * argv[])
if (command == "e") {
new_entry.reset(journal->derive_entry(argc - index, &argv[index]));
} else {
std::list<std::string> account_include_regexps;
std::list<std::string> account_exclude_regexps;
std::list<std::string> payee_include_regexps;
std::list<std::string> payee_exclude_regexps;
// Treat the remaining command-line arguments as regular
// expressions, used for refining report results.
for (; index < argc; index++) {
int start = index;
for (; index < argc; index++)
if (std::strcmp(argv[index], "--") == 0) {
index++;
break;
}
if (! show_expanded && command == "b")
show_expanded = true;
if (argv[index][0] == '-')
account_exclude_regexps.push_back(argv[index] + 1);
else
account_include_regexps.push_back(argv[index]);
if (start < index) {
std::list<std::string> regexps(&argv[start], &argv[index]);
std::string pred = regexps_to_predicate(regexps.begin(), regexps.end());
if (! pred.empty()) {
if (! predicate.empty())
predicate += "&";
predicate += pred;
}
}
for (; index < argc; index++) {
if (! show_expanded && command == "b")
show_expanded = true;
if (argv[index][0] == '-')
payee_exclude_regexps.push_back(argv[index] + 1);
else
payee_include_regexps.push_back(argv[index]);
if (index < argc) {
std::list<std::string> regexps(&argv[index], &argv[argc]);
std::string pred = regexps_to_predicate(regexps.begin(), regexps.end(),
false);
if (! pred.empty()) {
if (! predicate.empty())
predicate += "&";
predicate += pred;
}
}
assemble_regexp_predicate(predicate_string, account_include_regexps);
assemble_regexp_predicate(predicate_string, account_exclude_regexps, true);
assemble_regexp_predicate(predicate_string, payee_include_regexps,
false, true);
assemble_regexp_predicate(predicate_string, payee_exclude_regexps,
true, true);
}
// Compile the predicates
if (! predicate_string.empty()) {
#ifdef DEBUG
if (debug)
std::cerr << "predicate = " << predicate_string << std::endl;
#endif
predicate.reset(parse_expr(predicate_string));
}
if (display_predicate_string.empty()) {
if (display_predicate.empty()) {
if (command == "b") {
if (! show_empty)
display_predicate_string = "T";
display_predicate = "T";
if (! show_expanded) {
if (! display_predicate_string.empty())
display_predicate_string += "&";
display_predicate_string += "!n";
if (! display_predicate.empty())
display_predicate += "&";
display_predicate += "!n";
}
}
else if (command == "E") {
display_predicate_string = "a";
display_predicate = "a";
}
}
if (! display_predicate_string.empty()) {
#ifdef DEBUG
if (debug)
std::cerr << "disp-pred = " << display_predicate_string << std::endl;
#endif
display_predicate.reset(parse_expr(display_predicate_string));
}
// Compile the sorting string
if (! sort_string.empty())
@ -647,8 +589,8 @@ int main(int argc, char * argv[])
if (command == "b") {
format_t format(first_line_format);
format_account formatter(std::cout, format, display_predicate.get());
walk_accounts(journal->master, formatter, predicate.get(),
format_account formatter(std::cout, format, display_predicate);
walk_accounts(journal->master, formatter, predicate,
xact_display_flags, show_subtotals, sort_order.get());
if (format_account::disp_subaccounts_p(journal->master)) {
@ -660,9 +602,8 @@ int main(int argc, char * argv[])
else if (command == "E") {
format_t format(first_line_format);
format_t nformat(next_lines_format);
format_equity formatter(std::cout, format, nformat,
display_predicate.get());
walk_accounts(journal->master, formatter, predicate.get(),
format_equity formatter(std::cout, format, nformat, display_predicate);
walk_accounts(journal->master, formatter, predicate,
xact_display_flags, true, sort_order.get());
}
else if (command == "e") {
@ -678,8 +619,7 @@ int main(int argc, char * argv[])
else {
format_t format(first_line_format);
format_t nformat(next_lines_format);
format_transaction formatter(std::cout, format, nformat,
display_predicate.get(),
format_transaction formatter(std::cout, format, nformat, display_predicate,
#ifdef COLLAPSED_REGISTER
! show_subtotals,
#endif
@ -689,15 +629,15 @@ int main(int argc, char * argv[])
changed_value_filter<format_transaction>
filtered_formatter(formatter);
walk_entries(journal->entries.begin(), journal->entries.end(),
filtered_formatter, predicate.get(), xact_display_flags);
filtered_formatter, predicate, xact_display_flags);
} else {
walk_entries(journal->entries.begin(), journal->entries.end(),
formatter, predicate.get(), xact_display_flags);
formatter, predicate, xact_display_flags);
}
} else {
transactions_deque transactions_pool;
walk_entries(journal->entries.begin(), journal->entries.end(),
collect_transactions(transactions_pool), predicate.get(),
collect_transactions(transactions_pool), predicate,
xact_display_flags);
std::stable_sort(transactions_pool.begin(), transactions_pool.end(),
compare_items<transaction_t>(sort_order.get()));

View file

@ -131,36 +131,23 @@ void parse_automated_transactions(std::istream& in, account_t * account,
automated_transactions_t& auto_xacts)
{
static char line[MAX_LINE + 1];
in.getline(line, MAX_LINE);
linenum++;
masks_list masks;
transactions_deque xacts;
while (! in.eof() && in.peek() == '=') {
in.getline(line, MAX_LINE);
linenum++;
char * p = line + 1;
p = skip_ws(p);
masks.push_back(mask_t(p));
}
transactions_list xacts;
while (! in.eof() && (in.peek() == ' ' || in.peek() == '\t')) {
while (! in.eof() && (in.peek() == ' ' || in.peek() == '\t'))
if (transaction_t * xact = parse_transaction(in, account, NULL)) {
if (! xact->amount)
throw parse_error(path, linenum,
"All automated transactions must have a value");
"All automated transactions must have values");
else
xacts.push_back(xact);
}
}
if (! masks.empty() && ! xacts.empty()) {
automated_transaction_t * auto_xact
= new automated_transaction_t(masks, xacts);
auto_xacts.add_automated_transaction(auto_xact);
}
if (! xacts.empty())
auto_xacts.
add_automated_transaction(new automated_transaction_t(line + 1, xacts));
}
bool finalize_entry(entry_t * entry)

View file

@ -2,6 +2,8 @@
#include "error.h"
#include "datetime.h"
#include <vector>
#include <pcre.h>
namespace ledger {
@ -22,6 +24,8 @@ mask_t::mask_t(const std::string& pat) : exclude(false)
}
pattern = p;
DEBUG_PRINT("valexpr.mask.parse", "pattern = '" << pattern << "'");
const char *error;
int erroffset;
regexp = pcre_compile(pattern.c_str(), PCRE_CASELESS,
@ -337,6 +341,16 @@ void node_t::compute(balance_t& result, const details_t& details) const
}
}
inline char peek_next_nonws(std::istream& in)
{
char c = in.peek();
while (! in.eof() && std::isspace(c) && c != '\n') {
in.get(c);
c = in.peek();
}
return c;
}
node_t * parse_term(std::istream& in);
inline node_t * parse_term(const char * p) {
@ -348,7 +362,7 @@ node_t * parse_term(std::istream& in)
{
node_t * node = NULL;
char c = in.peek();
char c = peek_next_nonws(in);
if (std::isdigit(c) || c == '.' || c == '{') {
std::string ident;
@ -425,14 +439,14 @@ node_t * parse_term(std::istream& in)
case 'P':
node = new node_t(node_t::F_VALUE);
if (in.peek() == '(') {
if (peek_next_nonws(in) == '(') {
in.get(c);
node->left = parse_expr(in);
if (in.peek() == ',') {
if (peek_next_nonws(in) == ',') {
in.get(c);
node->right = parse_expr(in);
}
if (in.peek() == ')')
if (peek_next_nonws(in) == ')')
in.get(c);
else
throw expr_error("Missing ')'");
@ -446,7 +460,7 @@ node_t * parse_term(std::istream& in)
std::string ident;
bool payee_mask = false;
c = in.peek();
c = peek_next_nonws(in);
if (c == '/') {
payee_mask = true;
in.get(c);
@ -474,7 +488,7 @@ node_t * parse_term(std::istream& in)
case '(':
node = parse_expr(in);
if (in.peek() == ')')
if (peek_next_nonws(in) == ')')
in.get(c);
else
throw expr_error("Missing ')'");
@ -515,7 +529,7 @@ node_t * parse_mul_expr(std::istream& in)
node = parse_term(in);
if (node && ! in.eof()) {
char c = in.peek();
char c = peek_next_nonws(in);
while (c == '*' || c == '/') {
in.get(c);
switch (c) {
@ -535,7 +549,7 @@ node_t * parse_mul_expr(std::istream& in)
break;
}
}
c = in.peek();
c = peek_next_nonws(in);
}
}
@ -549,7 +563,7 @@ node_t * parse_add_expr(std::istream& in)
node = parse_mul_expr(in);
if (node && ! in.eof()) {
char c = in.peek();
char c = peek_next_nonws(in);
while (c == '+' || c == '-') {
in.get(c);
switch (c) {
@ -569,7 +583,7 @@ node_t * parse_add_expr(std::istream& in)
break;
}
}
c = in.peek();
c = peek_next_nonws(in);
}
}
@ -580,7 +594,7 @@ node_t * parse_logic_expr(std::istream& in)
{
node_t * node = NULL;
if (in.peek() == '!') {
if (peek_next_nonws(in) == '!') {
char c;
in.get(c);
node = new node_t(node_t::O_NOT);
@ -591,7 +605,7 @@ node_t * parse_logic_expr(std::istream& in)
node = parse_add_expr(in);
if (node && ! in.eof()) {
char c = in.peek();
char c = peek_next_nonws(in);
if (c == '=' || c == '<' || c == '>') {
in.get(c);
switch (c) {
@ -606,7 +620,7 @@ node_t * parse_logic_expr(std::istream& in)
case '<': {
node_t * prev = node;
node = new node_t(node_t::O_LT);
if (in.peek() == '=') {
if (peek_next_nonws(in) == '=') {
in.get(c);
node->type = node_t::O_LTE;
}
@ -618,7 +632,7 @@ node_t * parse_logic_expr(std::istream& in)
case '>': {
node_t * prev = node;
node = new node_t(node_t::O_GT);
if (in.peek() == '=') {
if (peek_next_nonws(in) == '=') {
in.get(c);
node->type = node_t::O_GTE;
}
@ -647,7 +661,7 @@ node_t * parse_expr(std::istream& in)
node = parse_logic_expr(in);
if (node && ! in.eof()) {
char c = in.peek();
char c = peek_next_nonws(in);
while (c == '&' || c == '|' || c == '?') {
in.get(c);
switch (c) {
@ -674,7 +688,7 @@ node_t * parse_expr(std::istream& in)
node_t * choices = new node_t(node_t::O_COL);
node->right = choices;
choices->left = parse_logic_expr(in);
c = in.peek();
c = peek_next_nonws(in);
if (c != ':') {
std::ostringstream err;
err << "Unexpected character '" << c << "'";
@ -692,21 +706,57 @@ node_t * parse_expr(std::istream& in)
throw expr_error(err.str());
}
}
c = in.peek();
c = peek_next_nonws(in);
}
}
return node;
}
} // namespace ledger
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.
#ifdef TEST
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;
}
namespace ledger {
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 += ")/";
}
static void dump_tree(std::ostream& out, node_t * node)
return pred;
}
#ifdef DEBUG_ENABLED
void dump_tree(std::ostream& out, const node_t * node)
{
switch (node->type) {
case node_t::CONSTANT_A:
@ -834,8 +884,12 @@ static void dump_tree(std::ostream& out, node_t * node)
}
}
#endif // DEBUG_ENABLED
} // namespace ledger
#ifdef TEST
int main(int argc, char *argv[])
{
ledger::dump_tree(std::cout, ledger::parse_expr(argv[1]));

View file

@ -134,13 +134,36 @@ inline node_t * find_node(node_t * node, node_t::kind_t type) {
return result;
}
#ifdef DEBUG_ENABLED
void dump_tree(std::ostream& out, const node_t * node);
#endif
template <typename T>
class item_predicate
{
const node_t * predicate;
public:
item_predicate(const node_t * _predicate) : predicate(_predicate) {}
item_predicate(const std::string& _predicate)
: predicate(_predicate.empty() ? NULL : parse_expr(_predicate)) {
#ifdef DEBUG_ENABLED
DEBUG_CLASS("valexpr.predicate.parse");
DEBUG_PRINT_("parsing: '" << _predicate << "'");
if (DEBUG_() && ledger::debug_stream) {
*ledger::debug_stream << "dump: ";
dump_tree(*ledger::debug_stream, predicate);
*ledger::debug_stream << std::endl;
}
#endif
}
item_predicate(const node_t * _predicate)
: predicate(_predicate) {}
~item_predicate() {
if (predicate)
delete predicate;
}
bool operator()(const T * item) const {
if (predicate) {
@ -153,6 +176,10 @@ 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
#endif // _REPORT_H

View file

@ -11,7 +11,7 @@ class sum_in_account
};
void calc__accounts(account_t * account,
item_predicate<transaction_t>& pred_functor,
const item_predicate<transaction_t>& pred_functor,
unsigned int flags)
{
sum_in_account functor;

20
walk.h
View file

@ -82,9 +82,9 @@ void handle_transaction(transaction_t * xact,
template <typename Function>
void walk_entries(entries_list::iterator begin,
entries_list::iterator end,
const Function& functor,
const node_t * predicate,
unsigned int flags)
const Function& functor,
const std::string& predicate,
unsigned int flags)
{
item_predicate<transaction_t> pred_functor(predicate);
@ -200,7 +200,7 @@ void for_each_account(account_t * account, const Function& functor)
}
void calc__accounts(account_t * account,
item_predicate<transaction_t>& pred_functor,
const item_predicate<transaction_t>& pred_functor,
unsigned int flags);
inline void sum__accounts(account_t * account)
@ -215,12 +215,12 @@ inline void sum__accounts(account_t * account)
}
template <typename Function>
void walk_accounts(account_t * account,
const Function& functor,
const node_t * predicate,
unsigned int flags,
const bool calc_subtotals,
const node_t * sort_order = NULL)
void walk_accounts(account_t * account,
const Function& functor,
const std::string& predicate,
unsigned int flags,
const bool calc_subtotals,
const node_t * sort_order = NULL)
{
item_predicate<transaction_t> pred_functor(predicate);