summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile7
-rw-r--r--NEWS12
-rw-r--r--autoxact.cc12
-rw-r--r--autoxact.h14
-rw-r--r--balance.h2
-rw-r--r--binary.cc48
-rw-r--r--error.h9
-rw-r--r--format.h26
-rw-r--r--ledger.h6
-rw-r--r--main.cc214
-rw-r--r--textual.cc29
-rw-r--r--valexpr.cc96
-rw-r--r--valexpr.h29
-rw-r--r--walk.cc2
-rw-r--r--walk.h20
15 files changed, 273 insertions, 253 deletions
diff --git a/Makefile b/Makefile
index 0ac560cd..0ae93fc2 100644
--- a/Makefile
+++ b/Makefile
@@ -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++ \
diff --git a/NEWS b/NEWS
index e99cf1ad..99261be2 100644
--- a/NEWS
+++ b/NEWS
@@ -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
diff --git a/autoxact.cc b/autoxact.cc
index c49d1d38..7dac4512 100644
--- a/autoxact.cc
+++ b/autoxact.cc
@@ -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
diff --git a/autoxact.h b/autoxact.h
index 717ebe96..76c67c3f 100644
--- a/autoxact.h
+++ b/autoxact.h
@@ -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;
diff --git a/balance.h b/balance.h
index 7fd3a770..888dd13e 100644
--- a/balance.h
+++ b/balance.h
@@ -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;
diff --git a/binary.cc b/binary.cc
index ee6bf3f0..b0b75513 100644
--- a/binary.cc
+++ b/binary.cc
@@ -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));
diff --git a/error.h b/error.h
index 4f506d70..d7a3eb28 100644
--- a/error.h
+++ b/error.h
@@ -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
diff --git a/format.h b/format.h
index 9828c5e7..107caad9 100644
--- a/format.h
+++ b/format.h
@@ -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),
diff --git a/ledger.h b/ledger.h
index c9bd37ba..9d34316b 100644
--- a/ledger.h
+++ b/ledger.h
@@ -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
diff --git a/main.cc b/main.cc
index 5d105cb3..4bc0e685 100644
--- a/main.cc
+++ b/main.cc
@@ -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()));
diff --git a/textual.cc b/textual.cc
index 2e8b0fd0..7970c23a 100644
--- a/textual.cc
+++ b/textual.cc
@@ -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;
-
- 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;
+ transactions_deque 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)
diff --git a/valexpr.cc b/valexpr.cc
index 15aa69f8..4180b176 100644
--- a/valexpr.cc
+++ b/valexpr.cc
@@ -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.
+
+ 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 += ")/";
+ }
-#ifdef TEST
+ return pred;
+}
-namespace ledger {
+#ifdef DEBUG_ENABLED
-static void dump_tree(std::ostream& out, node_t * node)
+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]));
diff --git a/valexpr.h b/valexpr.h
index 17ecc123..abfd635e 100644
--- a/valexpr.h
+++ b/valexpr.h
@@ -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
diff --git a/walk.cc b/walk.cc
index 5b923a86..88c423ff 100644
--- a/walk.cc
+++ b/walk.cc
@@ -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;
diff --git a/walk.h b/walk.h
index 7ad8264c..f54138df 100644
--- a/walk.h
+++ b/walk.h
@@ -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);