new debug code; automated transactions now use value expression predicates
This commit is contained in:
parent
799e97e420
commit
7a1d0d4614
15 changed files with 273 additions and 253 deletions
7
Makefile
7
Makefile
|
|
@ -4,6 +4,7 @@ CODE = account.cc \
|
||||||
balance.cc \
|
balance.cc \
|
||||||
binary.cc \
|
binary.cc \
|
||||||
datetime.cc \
|
datetime.cc \
|
||||||
|
debug.cc \
|
||||||
error.cc \
|
error.cc \
|
||||||
format.cc \
|
format.cc \
|
||||||
ledger.cc \
|
ledger.cc \
|
||||||
|
|
@ -17,9 +18,9 @@ OBJS = $(patsubst %.cc,%.o,$(CODE))
|
||||||
CXX = g++
|
CXX = g++
|
||||||
|
|
||||||
CFLAGS = -Wall -ansi -pedantic
|
CFLAGS = -Wall -ansi -pedantic
|
||||||
#DFLAGS = -O3 -fomit-frame-pointer
|
#DFLAGS = -O3 -fomit-frame-pointer -DRELEASE_LEVEL=0
|
||||||
DFLAGS = -g -DDEBUG=1
|
DFLAGS = -g -DRELEASE_LEVEL=4
|
||||||
#DFLAGS = -g -DDEBUG=1 -pg
|
#DFLAGS = -g -DRELEASE_LEVEL=2 -pg
|
||||||
|
|
||||||
INCS = -I/sw/include \
|
INCS = -I/sw/include \
|
||||||
-I/usr/include/gcc/darwin/3.3/c++ \
|
-I/usr/include/gcc/darwin/3.3/c++ \
|
||||||
|
|
|
||||||
12
NEWS
12
NEWS
|
|
@ -54,7 +54,7 @@
|
||||||
-W Report the trend, with older values affecting the trend less
|
-W Report the trend, with older values affecting the trend less
|
||||||
-X Report expected amount for the next transaction
|
-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:
|
be changed using -t and -T and an expression string composed of:
|
||||||
|
|
||||||
a amount
|
a amount
|
||||||
|
|
@ -142,6 +142,16 @@
|
||||||
%?10d %?-.20p %-.22a %12.66t %12.80T
|
%?10d %?-.20p %-.22a %12.66t %12.80T
|
||||||
%20T %-a
|
%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)
|
* 1.7 (never released)
|
||||||
|
|
||||||
- Pricing histories are now supported, so that ledger remembers
|
- Pricing histories are now supported, so that ledger remembers
|
||||||
|
|
|
||||||
12
autoxact.cc
12
autoxact.cc
|
|
@ -4,11 +4,14 @@ namespace ledger {
|
||||||
|
|
||||||
void automated_transaction_t::extend_entry(entry_t * entry)
|
void automated_transaction_t::extend_entry(entry_t * entry)
|
||||||
{
|
{
|
||||||
for (transactions_list::iterator i = entry->transactions.begin();
|
transactions_deque initial_xacts(entry->transactions.begin(),
|
||||||
i != entry->transactions.end();
|
entry->transactions.end());
|
||||||
|
|
||||||
|
for (transactions_deque::iterator i = initial_xacts.begin();
|
||||||
|
i != initial_xacts.end();
|
||||||
i++)
|
i++)
|
||||||
if (matches(masks, *((*i)->account))) {
|
if (predicate(*i))
|
||||||
for (transactions_list::iterator t = transactions.begin();
|
for (transactions_deque::iterator t = transactions.begin();
|
||||||
t != transactions.end();
|
t != transactions.end();
|
||||||
t++) {
|
t++) {
|
||||||
amount_t amt;
|
amount_t amt;
|
||||||
|
|
@ -23,6 +26,5 @@ void automated_transaction_t::extend_entry(entry_t * entry)
|
||||||
entry->add_transaction(xact);
|
entry->add_transaction(xact);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace ledger
|
} // namespace ledger
|
||||||
|
|
|
||||||
14
autoxact.h
14
autoxact.h
|
|
@ -8,15 +8,17 @@
|
||||||
|
|
||||||
namespace ledger {
|
namespace ledger {
|
||||||
|
|
||||||
|
typedef std::deque<transaction_t *> transactions_deque;
|
||||||
|
|
||||||
class automated_transaction_t
|
class automated_transaction_t
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
masks_list masks;
|
item_predicate<transaction_t> predicate;
|
||||||
transactions_list transactions;
|
transactions_deque transactions;
|
||||||
|
|
||||||
automated_transaction_t(masks_list& _masks,
|
automated_transaction_t(const std::string& _predicate,
|
||||||
transactions_list& _transactions) {
|
transactions_deque& _transactions)
|
||||||
masks.insert(masks.begin(), _masks.begin(), _masks.end());
|
: predicate(_predicate) {
|
||||||
transactions.insert(transactions.begin(),
|
transactions.insert(transactions.begin(),
|
||||||
_transactions.begin(), _transactions.end());
|
_transactions.begin(), _transactions.end());
|
||||||
// Take over ownership of the pointers
|
// Take over ownership of the pointers
|
||||||
|
|
@ -24,7 +26,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
~automated_transaction_t() {
|
~automated_transaction_t() {
|
||||||
for (transactions_list::iterator i = transactions.begin();
|
for (transactions_deque::iterator i = transactions.begin();
|
||||||
i != transactions.end();
|
i != transactions.end();
|
||||||
i++)
|
i++)
|
||||||
delete *i;
|
delete *i;
|
||||||
|
|
|
||||||
|
|
@ -352,7 +352,7 @@ inline balance_t abs(const balance_t& bal) {
|
||||||
return temp;
|
return temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG_ENABLED
|
||||||
inline std::ostream& operator<<(std::ostream& out, const balance_t& bal) {
|
inline std::ostream& operator<<(std::ostream& out, const balance_t& bal) {
|
||||||
bal.write(out, 12);
|
bal.write(out, 12);
|
||||||
return out;
|
return out;
|
||||||
|
|
|
||||||
48
binary.cc
48
binary.cc
|
|
@ -29,7 +29,7 @@ void read_binary_amount(std::istream& in, amount_t& amt)
|
||||||
{
|
{
|
||||||
unsigned long id;
|
unsigned long id;
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG_ENABLED
|
||||||
{
|
{
|
||||||
unsigned short guard;
|
unsigned short guard;
|
||||||
in.read((char *)&guard, sizeof(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);
|
amt.read_quantity(in);
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG_ENABLED
|
||||||
{
|
{
|
||||||
unsigned short guard;
|
unsigned short guard;
|
||||||
in.read((char *)&guard, sizeof(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;
|
unsigned long id;
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG_ENABLED
|
||||||
{
|
{
|
||||||
unsigned short guard;
|
unsigned short guard;
|
||||||
in.read((char *)&guard, sizeof(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;
|
xact->note = buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG_ENABLED
|
||||||
{
|
{
|
||||||
unsigned short guard;
|
unsigned short guard;
|
||||||
in.read((char *)&guard, sizeof(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;
|
entry_t * entry = new entry_t;
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG_ENABLED
|
||||||
{
|
{
|
||||||
unsigned short guard;
|
unsigned short guard;
|
||||||
in.read((char *)&guard, sizeof(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);
|
entry->transactions.push_back(xact);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG_ENABLED
|
||||||
{
|
{
|
||||||
unsigned short guard;
|
unsigned short guard;
|
||||||
in.read((char *)&guard, sizeof(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;
|
commodity_t * commodity = new commodity_t;
|
||||||
commodities.push_back(commodity);
|
commodities.push_back(commodity);
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG_ENABLED
|
||||||
{
|
{
|
||||||
unsigned short guard;
|
unsigned short guard;
|
||||||
in.read((char *)&guard, sizeof(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);
|
read_binary_amount(in, commodity->conversion);
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG_ENABLED
|
||||||
{
|
{
|
||||||
unsigned short guard;
|
unsigned short guard;
|
||||||
in.read((char *)&guard, sizeof(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);
|
account_t * acct = new account_t(NULL);
|
||||||
accounts.push_back(acct);
|
accounts.push_back(acct);
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG_ENABLED
|
||||||
{
|
{
|
||||||
unsigned short guard;
|
unsigned short guard;
|
||||||
in.read((char *)&guard, sizeof(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);
|
acct->add_account(child);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG_ENABLED
|
||||||
{
|
{
|
||||||
unsigned short guard;
|
unsigned short guard;
|
||||||
in.read((char *)&guard, sizeof(guard));
|
in.read((char *)&guard, sizeof(guard));
|
||||||
|
|
@ -296,7 +296,7 @@ unsigned int read_binary_journal(std::istream& in,
|
||||||
if (magic != binary_magic_number)
|
if (magic != binary_magic_number)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG_ENABLED
|
||||||
{
|
{
|
||||||
unsigned short guard;
|
unsigned short guard;
|
||||||
in.read((char *)&guard, sizeof(guard));
|
in.read((char *)&guard, sizeof(guard));
|
||||||
|
|
@ -356,7 +356,7 @@ unsigned int read_binary_journal(std::istream& in,
|
||||||
journal->entries.push_back(entry);
|
journal->entries.push_back(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG_ENABLED
|
||||||
{
|
{
|
||||||
unsigned short guard;
|
unsigned short guard;
|
||||||
in.read((char *)&guard, sizeof(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)
|
void write_binary_amount(std::ostream& out, const amount_t& amt)
|
||||||
{
|
{
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG_ENABLED
|
||||||
{
|
{
|
||||||
unsigned short guard = 0x1001;
|
unsigned short guard = 0x1001;
|
||||||
out.write((char *)&guard, sizeof(guard));
|
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);
|
amt.write_quantity(out);
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG_ENABLED
|
||||||
{
|
{
|
||||||
unsigned short guard = 0x1002;
|
unsigned short guard = 0x1002;
|
||||||
out.write((char *)&guard, sizeof(guard));
|
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)
|
void write_binary_transaction(std::ostream& out, transaction_t * xact)
|
||||||
{
|
{
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG_ENABLED
|
||||||
{
|
{
|
||||||
unsigned short guard = 0x1003;
|
unsigned short guard = 0x1003;
|
||||||
out.write((char *)&guard, sizeof(guard));
|
out.write((char *)&guard, sizeof(guard));
|
||||||
|
|
@ -416,7 +416,7 @@ void write_binary_transaction(std::ostream& out, transaction_t * xact)
|
||||||
if (len)
|
if (len)
|
||||||
out.write(xact->note.c_str(), len);
|
out.write(xact->note.c_str(), len);
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG_ENABLED
|
||||||
{
|
{
|
||||||
unsigned short guard = 0x1004;
|
unsigned short guard = 0x1004;
|
||||||
out.write((char *)&guard, sizeof(guard));
|
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)
|
void write_binary_entry(std::ostream& out, entry_t * entry)
|
||||||
{
|
{
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG_ENABLED
|
||||||
{
|
{
|
||||||
unsigned short guard = 0x1005;
|
unsigned short guard = 0x1005;
|
||||||
out.write((char *)&guard, sizeof(guard));
|
out.write((char *)&guard, sizeof(guard));
|
||||||
|
|
@ -454,7 +454,7 @@ void write_binary_entry(std::ostream& out, entry_t * entry)
|
||||||
i++)
|
i++)
|
||||||
write_binary_transaction(out, *i);
|
write_binary_transaction(out, *i);
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG_ENABLED
|
||||||
{
|
{
|
||||||
unsigned short guard = 0x1006;
|
unsigned short guard = 0x1006;
|
||||||
out.write((char *)&guard, sizeof(guard));
|
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)
|
void write_binary_commodity(std::ostream& out, commodity_t * commodity)
|
||||||
{
|
{
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG_ENABLED
|
||||||
{
|
{
|
||||||
unsigned short guard = 0x1007;
|
unsigned short guard = 0x1007;
|
||||||
out.write((char *)&guard, sizeof(guard));
|
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);
|
write_binary_amount(out, commodity->conversion);
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG_ENABLED
|
||||||
{
|
{
|
||||||
unsigned short guard = 0x1008;
|
unsigned short guard = 0x1008;
|
||||||
out.write((char *)&guard, sizeof(guard));
|
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)
|
void write_binary_account(std::ostream& out, account_t * account)
|
||||||
{
|
{
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG_ENABLED
|
||||||
{
|
{
|
||||||
unsigned short guard = 0x1009;
|
unsigned short guard = 0x1009;
|
||||||
out.write((char *)&guard, sizeof(guard));
|
out.write((char *)&guard, sizeof(guard));
|
||||||
|
|
@ -552,7 +552,7 @@ void write_binary_account(std::ostream& out, account_t * account)
|
||||||
i++)
|
i++)
|
||||||
write_binary_account(out, (*i).second);
|
write_binary_account(out, (*i).second);
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG_ENABLED
|
||||||
{
|
{
|
||||||
unsigned short guard = 0x1010;
|
unsigned short guard = 0x1010;
|
||||||
out.write((char *)&guard, sizeof(guard));
|
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));
|
out.write((char *)&binary_magic_number, sizeof(binary_magic_number));
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG_ENABLED
|
||||||
{
|
{
|
||||||
unsigned short guard = 0x1011;
|
unsigned short guard = 0x1011;
|
||||||
out.write((char *)&guard, sizeof(guard));
|
out.write((char *)&guard, sizeof(guard));
|
||||||
|
|
@ -613,7 +613,7 @@ void write_binary_journal(std::ostream& out, journal_t * journal,
|
||||||
i++)
|
i++)
|
||||||
write_binary_entry(out, *i);
|
write_binary_entry(out, *i);
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG_ENABLED
|
||||||
{
|
{
|
||||||
unsigned short guard = 0x1012;
|
unsigned short guard = 0x1012;
|
||||||
out.write((char *)&guard, sizeof(guard));
|
out.write((char *)&guard, sizeof(guard));
|
||||||
|
|
|
||||||
9
error.h
9
error.h
|
|
@ -6,15 +6,6 @@
|
||||||
#include <exception>
|
#include <exception>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
#include <cassert>
|
|
||||||
#else
|
|
||||||
#ifdef assert
|
|
||||||
#undef assert
|
|
||||||
#endif
|
|
||||||
#define assert(x)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace ledger {
|
namespace ledger {
|
||||||
|
|
||||||
class error : public std::exception
|
class error : public std::exception
|
||||||
|
|
|
||||||
6
format.h
6
format.h
|
|
@ -107,7 +107,7 @@ class format_transaction
|
||||||
format_transaction(std::ostream& _output_stream,
|
format_transaction(std::ostream& _output_stream,
|
||||||
const format_t& _first_line_format,
|
const format_t& _first_line_format,
|
||||||
const format_t& _next_lines_format,
|
const format_t& _next_lines_format,
|
||||||
const node_t * display_predicate = NULL,
|
const std::string& display_predicate = NULL,
|
||||||
#ifdef COLLAPSED_REGISTER
|
#ifdef COLLAPSED_REGISTER
|
||||||
const bool _collapsed = false,
|
const bool _collapsed = false,
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -200,7 +200,7 @@ class format_account
|
||||||
public:
|
public:
|
||||||
format_account(std::ostream& _output_stream,
|
format_account(std::ostream& _output_stream,
|
||||||
const format_t& _format,
|
const format_t& _format,
|
||||||
const node_t * display_predicate = NULL)
|
const std::string& display_predicate = NULL)
|
||||||
: output_stream(_output_stream), format(_format),
|
: output_stream(_output_stream), format(_format),
|
||||||
disp_pred_functor(display_predicate) {}
|
disp_pred_functor(display_predicate) {}
|
||||||
|
|
||||||
|
|
@ -240,7 +240,7 @@ class format_equity
|
||||||
format_equity(std::ostream& _output_stream,
|
format_equity(std::ostream& _output_stream,
|
||||||
const format_t& _first_line_format,
|
const format_t& _first_line_format,
|
||||||
const format_t& _next_lines_format,
|
const format_t& _next_lines_format,
|
||||||
const node_t * display_predicate = NULL)
|
const std::string& display_predicate = NULL)
|
||||||
: output_stream(_output_stream),
|
: output_stream(_output_stream),
|
||||||
first_line_format(_first_line_format),
|
first_line_format(_first_line_format),
|
||||||
next_lines_format(_next_lines_format),
|
next_lines_format(_next_lines_format),
|
||||||
|
|
|
||||||
6
ledger.h
6
ledger.h
|
|
@ -19,6 +19,12 @@
|
||||||
#include "amount.h"
|
#include "amount.h"
|
||||||
#include "balance.h"
|
#include "balance.h"
|
||||||
|
|
||||||
|
#ifdef RELEASE_LEVEL
|
||||||
|
#if RELEASE_LEVEL >= 2
|
||||||
|
#include "debug.h"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace ledger {
|
namespace ledger {
|
||||||
|
|
||||||
#define TRANSACTION_NORMAL 0x00
|
#define TRANSACTION_NORMAL 0x00
|
||||||
|
|
|
||||||
210
main.cc
210
main.cc
|
|
@ -102,34 +102,6 @@ void download_price_quote(commodity_t * commodity,
|
||||||
} // namespace ledger
|
} // 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)
|
static void show_version(std::ostream& out)
|
||||||
{
|
{
|
||||||
out
|
out
|
||||||
|
|
@ -187,12 +159,10 @@ 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> predicate;
|
|
||||||
std::auto_ptr<node_t> display_predicate;
|
|
||||||
std::auto_ptr<node_t> sort_order;
|
std::auto_ptr<node_t> sort_order;
|
||||||
|
|
||||||
std::string predicate_string;
|
std::string predicate;
|
||||||
std::string display_predicate_string;
|
std::string display_predicate;
|
||||||
std::string format_string;
|
std::string format_string;
|
||||||
std::string sort_string;
|
std::string sort_string;
|
||||||
std::string value_expr = "a";
|
std::string value_expr = "a";
|
||||||
|
|
@ -207,8 +177,11 @@ int main(int argc, char * argv[])
|
||||||
bool show_commodities_revalued = false;
|
bool show_commodities_revalued = false;
|
||||||
bool show_commodities_revalued_only = false;
|
bool show_commodities_revalued_only = false;
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG_ENABLED
|
||||||
bool debug = false;
|
if (char * p = std::getenv("DEBUG_FILE")) {
|
||||||
|
debug_stream = new std::ofstream(p);
|
||||||
|
free_debug_stream = true;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Initialize some variables based on environment variable settings
|
// Initialize some variables based on environment variable settings
|
||||||
|
|
@ -251,19 +224,13 @@ int main(int argc, char * argv[])
|
||||||
int c, index;
|
int c, index;
|
||||||
while (-1 !=
|
while (-1 !=
|
||||||
(c = getopt(argc, argv,
|
(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)) {
|
switch (char(c)) {
|
||||||
// Basic options
|
// Basic options
|
||||||
case 'h':
|
case 'h':
|
||||||
show_help(std::cout);
|
show_help(std::cout);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
case 'z':
|
|
||||||
debug = 1;
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
case 'v':
|
case 'v':
|
||||||
show_version(std::cout);
|
show_version(std::cout);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -278,48 +245,48 @@ int main(int argc, char * argv[])
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'b':
|
case 'b':
|
||||||
if (! predicate_string.empty())
|
if (! predicate.empty())
|
||||||
predicate_string += "&";
|
predicate += "&";
|
||||||
predicate_string += "(d>=[";
|
predicate += "(d>=[";
|
||||||
predicate_string += optarg;
|
predicate += optarg;
|
||||||
predicate_string += "])";
|
predicate += "])";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'e':
|
case 'e':
|
||||||
if (! predicate_string.empty())
|
if (! predicate.empty())
|
||||||
predicate_string += "&";
|
predicate += "&";
|
||||||
predicate_string += "(d<[";
|
predicate += "(d<[";
|
||||||
predicate_string += optarg;
|
predicate += optarg;
|
||||||
predicate_string += "])";
|
predicate += "])";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'c': {
|
case 'c': {
|
||||||
if (! predicate_string.empty())
|
if (! predicate.empty())
|
||||||
predicate_string += "&";
|
predicate += "&";
|
||||||
predicate_string += "(d<";
|
predicate += "(d<";
|
||||||
std::ostringstream now;
|
std::ostringstream now;
|
||||||
now << std::time(NULL);
|
now << std::time(NULL);
|
||||||
predicate_string += now.str();
|
predicate += now.str();
|
||||||
predicate_string += ")";
|
predicate += ")";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'C':
|
case 'C':
|
||||||
if (! predicate_string.empty())
|
if (! predicate.empty())
|
||||||
predicate_string += "&";
|
predicate += "&";
|
||||||
predicate_string += "X";
|
predicate += "X";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'U':
|
case 'U':
|
||||||
if (! predicate_string.empty())
|
if (! predicate.empty())
|
||||||
predicate_string += "&";
|
predicate += "&";
|
||||||
predicate_string += "!X";
|
predicate += "!X";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'R':
|
case 'R':
|
||||||
if (! predicate_string.empty())
|
if (! predicate.empty())
|
||||||
predicate_string += "&";
|
predicate += "&";
|
||||||
predicate_string += "R";
|
predicate += "R";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Customizing output
|
// Customizing output
|
||||||
|
|
@ -348,19 +315,19 @@ int main(int argc, char * argv[])
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'l':
|
case 'l':
|
||||||
if (! predicate_string.empty())
|
if (! predicate.empty())
|
||||||
predicate_string += "&";
|
predicate += "&";
|
||||||
predicate_string += "(";
|
predicate += "(";
|
||||||
predicate_string += optarg;
|
predicate += optarg;
|
||||||
predicate_string += ")";
|
predicate += ")";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'd':
|
case 'd':
|
||||||
if (! display_predicate_string.empty())
|
if (! display_predicate.empty())
|
||||||
display_predicate_string += "&";
|
display_predicate += "&";
|
||||||
display_predicate_string += "(";
|
display_predicate += "(";
|
||||||
display_predicate_string += optarg;
|
display_predicate += optarg;
|
||||||
display_predicate_string += ")";
|
display_predicate += ")";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Commodity reporting
|
// Commodity reporting
|
||||||
|
|
@ -518,81 +485,56 @@ int main(int argc, char * argv[])
|
||||||
if (command == "e") {
|
if (command == "e") {
|
||||||
new_entry.reset(journal->derive_entry(argc - index, &argv[index]));
|
new_entry.reset(journal->derive_entry(argc - index, &argv[index]));
|
||||||
} else {
|
} 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
|
// Treat the remaining command-line arguments as regular
|
||||||
// expressions, used for refining report results.
|
// expressions, used for refining report results.
|
||||||
|
|
||||||
for (; index < argc; index++) {
|
int start = index;
|
||||||
|
for (; index < argc; index++)
|
||||||
if (std::strcmp(argv[index], "--") == 0) {
|
if (std::strcmp(argv[index], "--") == 0) {
|
||||||
index++;
|
index++;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! show_expanded && command == "b")
|
if (start < index) {
|
||||||
show_expanded = true;
|
std::list<std::string> regexps(&argv[start], &argv[index]);
|
||||||
|
std::string pred = regexps_to_predicate(regexps.begin(), regexps.end());
|
||||||
if (argv[index][0] == '-')
|
if (! pred.empty()) {
|
||||||
account_exclude_regexps.push_back(argv[index] + 1);
|
if (! predicate.empty())
|
||||||
else
|
predicate += "&";
|
||||||
account_include_regexps.push_back(argv[index]);
|
predicate += pred;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (; index < argc; index++) {
|
if (index < argc) {
|
||||||
if (! show_expanded && command == "b")
|
std::list<std::string> regexps(&argv[index], &argv[argc]);
|
||||||
show_expanded = true;
|
std::string pred = regexps_to_predicate(regexps.begin(), regexps.end(),
|
||||||
|
false);
|
||||||
if (argv[index][0] == '-')
|
if (! pred.empty()) {
|
||||||
payee_exclude_regexps.push_back(argv[index] + 1);
|
if (! predicate.empty())
|
||||||
else
|
predicate += "&";
|
||||||
payee_include_regexps.push_back(argv[index]);
|
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
|
// Compile the predicates
|
||||||
|
|
||||||
if (! predicate_string.empty()) {
|
if (display_predicate.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 (command == "b") {
|
if (command == "b") {
|
||||||
if (! show_empty)
|
if (! show_empty)
|
||||||
display_predicate_string = "T";
|
display_predicate = "T";
|
||||||
|
|
||||||
if (! show_expanded) {
|
if (! show_expanded) {
|
||||||
if (! display_predicate_string.empty())
|
if (! display_predicate.empty())
|
||||||
display_predicate_string += "&";
|
display_predicate += "&";
|
||||||
display_predicate_string += "!n";
|
display_predicate += "!n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (command == "E") {
|
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
|
// Compile the sorting string
|
||||||
|
|
||||||
if (! sort_string.empty())
|
if (! sort_string.empty())
|
||||||
|
|
@ -647,8 +589,8 @@ int main(int argc, char * argv[])
|
||||||
|
|
||||||
if (command == "b") {
|
if (command == "b") {
|
||||||
format_t format(first_line_format);
|
format_t format(first_line_format);
|
||||||
format_account formatter(std::cout, format, display_predicate.get());
|
format_account formatter(std::cout, format, display_predicate);
|
||||||
walk_accounts(journal->master, formatter, predicate.get(),
|
walk_accounts(journal->master, formatter, predicate,
|
||||||
xact_display_flags, show_subtotals, sort_order.get());
|
xact_display_flags, show_subtotals, sort_order.get());
|
||||||
|
|
||||||
if (format_account::disp_subaccounts_p(journal->master)) {
|
if (format_account::disp_subaccounts_p(journal->master)) {
|
||||||
|
|
@ -660,9 +602,8 @@ int main(int argc, char * argv[])
|
||||||
else if (command == "E") {
|
else if (command == "E") {
|
||||||
format_t format(first_line_format);
|
format_t format(first_line_format);
|
||||||
format_t nformat(next_lines_format);
|
format_t nformat(next_lines_format);
|
||||||
format_equity formatter(std::cout, format, nformat,
|
format_equity formatter(std::cout, format, nformat, display_predicate);
|
||||||
display_predicate.get());
|
walk_accounts(journal->master, formatter, predicate,
|
||||||
walk_accounts(journal->master, formatter, predicate.get(),
|
|
||||||
xact_display_flags, true, sort_order.get());
|
xact_display_flags, true, sort_order.get());
|
||||||
}
|
}
|
||||||
else if (command == "e") {
|
else if (command == "e") {
|
||||||
|
|
@ -678,8 +619,7 @@ int main(int argc, char * argv[])
|
||||||
else {
|
else {
|
||||||
format_t format(first_line_format);
|
format_t format(first_line_format);
|
||||||
format_t nformat(next_lines_format);
|
format_t nformat(next_lines_format);
|
||||||
format_transaction formatter(std::cout, format, nformat,
|
format_transaction formatter(std::cout, format, nformat, display_predicate,
|
||||||
display_predicate.get(),
|
|
||||||
#ifdef COLLAPSED_REGISTER
|
#ifdef COLLAPSED_REGISTER
|
||||||
! show_subtotals,
|
! show_subtotals,
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -689,15 +629,15 @@ int main(int argc, char * argv[])
|
||||||
changed_value_filter<format_transaction>
|
changed_value_filter<format_transaction>
|
||||||
filtered_formatter(formatter);
|
filtered_formatter(formatter);
|
||||||
walk_entries(journal->entries.begin(), journal->entries.end(),
|
walk_entries(journal->entries.begin(), journal->entries.end(),
|
||||||
filtered_formatter, predicate.get(), xact_display_flags);
|
filtered_formatter, predicate, xact_display_flags);
|
||||||
} else {
|
} else {
|
||||||
walk_entries(journal->entries.begin(), journal->entries.end(),
|
walk_entries(journal->entries.begin(), journal->entries.end(),
|
||||||
formatter, predicate.get(), xact_display_flags);
|
formatter, predicate, xact_display_flags);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
transactions_deque transactions_pool;
|
transactions_deque transactions_pool;
|
||||||
walk_entries(journal->entries.begin(), journal->entries.end(),
|
walk_entries(journal->entries.begin(), journal->entries.end(),
|
||||||
collect_transactions(transactions_pool), predicate.get(),
|
collect_transactions(transactions_pool), predicate,
|
||||||
xact_display_flags);
|
xact_display_flags);
|
||||||
std::stable_sort(transactions_pool.begin(), transactions_pool.end(),
|
std::stable_sort(transactions_pool.begin(), transactions_pool.end(),
|
||||||
compare_items<transaction_t>(sort_order.get()));
|
compare_items<transaction_t>(sort_order.get()));
|
||||||
|
|
|
||||||
25
textual.cc
25
textual.cc
|
|
@ -131,36 +131,23 @@ void parse_automated_transactions(std::istream& in, account_t * account,
|
||||||
automated_transactions_t& auto_xacts)
|
automated_transactions_t& auto_xacts)
|
||||||
{
|
{
|
||||||
static char line[MAX_LINE + 1];
|
static char line[MAX_LINE + 1];
|
||||||
|
|
||||||
masks_list masks;
|
|
||||||
|
|
||||||
while (! in.eof() && in.peek() == '=') {
|
|
||||||
in.getline(line, MAX_LINE);
|
in.getline(line, MAX_LINE);
|
||||||
linenum++;
|
linenum++;
|
||||||
|
|
||||||
char * p = line + 1;
|
transactions_deque xacts;
|
||||||
p = skip_ws(p);
|
|
||||||
|
|
||||||
masks.push_back(mask_t(p));
|
while (! in.eof() && (in.peek() == ' ' || in.peek() == '\t'))
|
||||||
}
|
|
||||||
|
|
||||||
transactions_list xacts;
|
|
||||||
|
|
||||||
while (! in.eof() && (in.peek() == ' ' || in.peek() == '\t')) {
|
|
||||||
if (transaction_t * xact = parse_transaction(in, account, NULL)) {
|
if (transaction_t * xact = parse_transaction(in, account, NULL)) {
|
||||||
if (! xact->amount)
|
if (! xact->amount)
|
||||||
throw parse_error(path, linenum,
|
throw parse_error(path, linenum,
|
||||||
"All automated transactions must have a value");
|
"All automated transactions must have values");
|
||||||
else
|
else
|
||||||
xacts.push_back(xact);
|
xacts.push_back(xact);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (! masks.empty() && ! xacts.empty()) {
|
if (! xacts.empty())
|
||||||
automated_transaction_t * auto_xact
|
auto_xacts.
|
||||||
= new automated_transaction_t(masks, xacts);
|
add_automated_transaction(new automated_transaction_t(line + 1, xacts));
|
||||||
auto_xacts.add_automated_transaction(auto_xact);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool finalize_entry(entry_t * entry)
|
bool finalize_entry(entry_t * entry)
|
||||||
|
|
|
||||||
96
valexpr.cc
96
valexpr.cc
|
|
@ -2,6 +2,8 @@
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
#include "datetime.h"
|
#include "datetime.h"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include <pcre.h>
|
#include <pcre.h>
|
||||||
|
|
||||||
namespace ledger {
|
namespace ledger {
|
||||||
|
|
@ -22,6 +24,8 @@ mask_t::mask_t(const std::string& pat) : exclude(false)
|
||||||
}
|
}
|
||||||
pattern = p;
|
pattern = p;
|
||||||
|
|
||||||
|
DEBUG_PRINT("valexpr.mask.parse", "pattern = '" << pattern << "'");
|
||||||
|
|
||||||
const char *error;
|
const char *error;
|
||||||
int erroffset;
|
int erroffset;
|
||||||
regexp = pcre_compile(pattern.c_str(), PCRE_CASELESS,
|
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);
|
node_t * parse_term(std::istream& in);
|
||||||
|
|
||||||
inline node_t * parse_term(const char * p) {
|
inline node_t * parse_term(const char * p) {
|
||||||
|
|
@ -348,7 +362,7 @@ node_t * parse_term(std::istream& in)
|
||||||
{
|
{
|
||||||
node_t * node = NULL;
|
node_t * node = NULL;
|
||||||
|
|
||||||
char c = in.peek();
|
char c = peek_next_nonws(in);
|
||||||
if (std::isdigit(c) || c == '.' || c == '{') {
|
if (std::isdigit(c) || c == '.' || c == '{') {
|
||||||
std::string ident;
|
std::string ident;
|
||||||
|
|
||||||
|
|
@ -425,14 +439,14 @@ node_t * parse_term(std::istream& in)
|
||||||
|
|
||||||
case 'P':
|
case 'P':
|
||||||
node = new node_t(node_t::F_VALUE);
|
node = new node_t(node_t::F_VALUE);
|
||||||
if (in.peek() == '(') {
|
if (peek_next_nonws(in) == '(') {
|
||||||
in.get(c);
|
in.get(c);
|
||||||
node->left = parse_expr(in);
|
node->left = parse_expr(in);
|
||||||
if (in.peek() == ',') {
|
if (peek_next_nonws(in) == ',') {
|
||||||
in.get(c);
|
in.get(c);
|
||||||
node->right = parse_expr(in);
|
node->right = parse_expr(in);
|
||||||
}
|
}
|
||||||
if (in.peek() == ')')
|
if (peek_next_nonws(in) == ')')
|
||||||
in.get(c);
|
in.get(c);
|
||||||
else
|
else
|
||||||
throw expr_error("Missing ')'");
|
throw expr_error("Missing ')'");
|
||||||
|
|
@ -446,7 +460,7 @@ node_t * parse_term(std::istream& in)
|
||||||
std::string ident;
|
std::string ident;
|
||||||
bool payee_mask = false;
|
bool payee_mask = false;
|
||||||
|
|
||||||
c = in.peek();
|
c = peek_next_nonws(in);
|
||||||
if (c == '/') {
|
if (c == '/') {
|
||||||
payee_mask = true;
|
payee_mask = true;
|
||||||
in.get(c);
|
in.get(c);
|
||||||
|
|
@ -474,7 +488,7 @@ node_t * parse_term(std::istream& in)
|
||||||
|
|
||||||
case '(':
|
case '(':
|
||||||
node = parse_expr(in);
|
node = parse_expr(in);
|
||||||
if (in.peek() == ')')
|
if (peek_next_nonws(in) == ')')
|
||||||
in.get(c);
|
in.get(c);
|
||||||
else
|
else
|
||||||
throw expr_error("Missing ')'");
|
throw expr_error("Missing ')'");
|
||||||
|
|
@ -515,7 +529,7 @@ node_t * parse_mul_expr(std::istream& in)
|
||||||
node = parse_term(in);
|
node = parse_term(in);
|
||||||
|
|
||||||
if (node && ! in.eof()) {
|
if (node && ! in.eof()) {
|
||||||
char c = in.peek();
|
char c = peek_next_nonws(in);
|
||||||
while (c == '*' || c == '/') {
|
while (c == '*' || c == '/') {
|
||||||
in.get(c);
|
in.get(c);
|
||||||
switch (c) {
|
switch (c) {
|
||||||
|
|
@ -535,7 +549,7 @@ node_t * parse_mul_expr(std::istream& in)
|
||||||
break;
|
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);
|
node = parse_mul_expr(in);
|
||||||
|
|
||||||
if (node && ! in.eof()) {
|
if (node && ! in.eof()) {
|
||||||
char c = in.peek();
|
char c = peek_next_nonws(in);
|
||||||
while (c == '+' || c == '-') {
|
while (c == '+' || c == '-') {
|
||||||
in.get(c);
|
in.get(c);
|
||||||
switch (c) {
|
switch (c) {
|
||||||
|
|
@ -569,7 +583,7 @@ node_t * parse_add_expr(std::istream& in)
|
||||||
break;
|
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;
|
node_t * node = NULL;
|
||||||
|
|
||||||
if (in.peek() == '!') {
|
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 node_t(node_t::O_NOT);
|
||||||
|
|
@ -591,7 +605,7 @@ node_t * parse_logic_expr(std::istream& in)
|
||||||
node = parse_add_expr(in);
|
node = parse_add_expr(in);
|
||||||
|
|
||||||
if (node && ! in.eof()) {
|
if (node && ! in.eof()) {
|
||||||
char c = in.peek();
|
char c = peek_next_nonws(in);
|
||||||
if (c == '=' || c == '<' || c == '>') {
|
if (c == '=' || c == '<' || c == '>') {
|
||||||
in.get(c);
|
in.get(c);
|
||||||
switch (c) {
|
switch (c) {
|
||||||
|
|
@ -606,7 +620,7 @@ node_t * parse_logic_expr(std::istream& in)
|
||||||
case '<': {
|
case '<': {
|
||||||
node_t * prev = node;
|
node_t * prev = node;
|
||||||
node = new node_t(node_t::O_LT);
|
node = new node_t(node_t::O_LT);
|
||||||
if (in.peek() == '=') {
|
if (peek_next_nonws(in) == '=') {
|
||||||
in.get(c);
|
in.get(c);
|
||||||
node->type = node_t::O_LTE;
|
node->type = node_t::O_LTE;
|
||||||
}
|
}
|
||||||
|
|
@ -618,7 +632,7 @@ node_t * parse_logic_expr(std::istream& in)
|
||||||
case '>': {
|
case '>': {
|
||||||
node_t * prev = node;
|
node_t * prev = node;
|
||||||
node = new node_t(node_t::O_GT);
|
node = new node_t(node_t::O_GT);
|
||||||
if (in.peek() == '=') {
|
if (peek_next_nonws(in) == '=') {
|
||||||
in.get(c);
|
in.get(c);
|
||||||
node->type = node_t::O_GTE;
|
node->type = node_t::O_GTE;
|
||||||
}
|
}
|
||||||
|
|
@ -647,7 +661,7 @@ node_t * parse_expr(std::istream& in)
|
||||||
node = parse_logic_expr(in);
|
node = parse_logic_expr(in);
|
||||||
|
|
||||||
if (node && ! in.eof()) {
|
if (node && ! in.eof()) {
|
||||||
char c = in.peek();
|
char c = peek_next_nonws(in);
|
||||||
while (c == '&' || c == '|' || c == '?') {
|
while (c == '&' || c == '|' || c == '?') {
|
||||||
in.get(c);
|
in.get(c);
|
||||||
switch (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_t * choices = new node_t(node_t::O_COL);
|
||||||
node->right = choices;
|
node->right = choices;
|
||||||
choices->left = parse_logic_expr(in);
|
choices->left = parse_logic_expr(in);
|
||||||
c = in.peek();
|
c = peek_next_nonws(in);
|
||||||
if (c != ':') {
|
if (c != ':') {
|
||||||
std::ostringstream err;
|
std::ostringstream err;
|
||||||
err << "Unexpected character '" << c << "'";
|
err << "Unexpected character '" << c << "'";
|
||||||
|
|
@ -692,21 +706,57 @@ node_t * parse_expr(std::istream& in)
|
||||||
throw expr_error(err.str());
|
throw expr_error(err.str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
c = in.peek();
|
c = peek_next_nonws(in);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return node;
|
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) {
|
switch (node->type) {
|
||||||
case node_t::CONSTANT_A:
|
case node_t::CONSTANT_A:
|
||||||
|
|
@ -834,8 +884,12 @@ static void dump_tree(std::ostream& out, node_t * node)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif // DEBUG_ENABLED
|
||||||
|
|
||||||
} // namespace ledger
|
} // namespace ledger
|
||||||
|
|
||||||
|
#ifdef TEST
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
ledger::dump_tree(std::cout, ledger::parse_expr(argv[1]));
|
ledger::dump_tree(std::cout, ledger::parse_expr(argv[1]));
|
||||||
|
|
|
||||||
29
valexpr.h
29
valexpr.h
|
|
@ -134,13 +134,36 @@ inline node_t * find_node(node_t * node, node_t::kind_t type) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG_ENABLED
|
||||||
|
void dump_tree(std::ostream& out, const node_t * node);
|
||||||
|
#endif
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class item_predicate
|
class item_predicate
|
||||||
{
|
{
|
||||||
const node_t * predicate;
|
const node_t * predicate;
|
||||||
|
|
||||||
public:
|
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 {
|
bool operator()(const T * item) const {
|
||||||
if (predicate) {
|
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
|
} // namespace report
|
||||||
|
|
||||||
#endif // _REPORT_H
|
#endif // _REPORT_H
|
||||||
|
|
|
||||||
2
walk.cc
2
walk.cc
|
|
@ -11,7 +11,7 @@ class sum_in_account
|
||||||
};
|
};
|
||||||
|
|
||||||
void calc__accounts(account_t * account,
|
void calc__accounts(account_t * account,
|
||||||
item_predicate<transaction_t>& pred_functor,
|
const item_predicate<transaction_t>& pred_functor,
|
||||||
unsigned int flags)
|
unsigned int flags)
|
||||||
{
|
{
|
||||||
sum_in_account functor;
|
sum_in_account functor;
|
||||||
|
|
|
||||||
6
walk.h
6
walk.h
|
|
@ -83,7 +83,7 @@ template <typename Function>
|
||||||
void walk_entries(entries_list::iterator begin,
|
void walk_entries(entries_list::iterator begin,
|
||||||
entries_list::iterator end,
|
entries_list::iterator end,
|
||||||
const Function& functor,
|
const Function& functor,
|
||||||
const node_t * predicate,
|
const std::string& predicate,
|
||||||
unsigned int flags)
|
unsigned int flags)
|
||||||
{
|
{
|
||||||
item_predicate<transaction_t> pred_functor(predicate);
|
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,
|
void calc__accounts(account_t * account,
|
||||||
item_predicate<transaction_t>& pred_functor,
|
const item_predicate<transaction_t>& pred_functor,
|
||||||
unsigned int flags);
|
unsigned int flags);
|
||||||
|
|
||||||
inline void sum__accounts(account_t * account)
|
inline void sum__accounts(account_t * account)
|
||||||
|
|
@ -217,7 +217,7 @@ inline void sum__accounts(account_t * account)
|
||||||
template <typename Function>
|
template <typename Function>
|
||||||
void walk_accounts(account_t * account,
|
void walk_accounts(account_t * account,
|
||||||
const Function& functor,
|
const Function& functor,
|
||||||
const node_t * predicate,
|
const std::string& predicate,
|
||||||
unsigned int flags,
|
unsigned int flags,
|
||||||
const bool calc_subtotals,
|
const bool calc_subtotals,
|
||||||
const node_t * sort_order = NULL)
|
const node_t * sort_order = NULL)
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue