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 \
|
||||
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
12
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
|
||||
|
|
|
|||
12
autoxact.cc
12
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
|
||||
|
|
|
|||
14
autoxact.h
14
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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
48
binary.cc
48
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));
|
||||
|
|
|
|||
9
error.h
9
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
|
||||
|
|
|
|||
26
format.h
26
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),
|
||||
|
|
|
|||
6
ledger.h
6
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
|
||||
|
|
|
|||
214
main.cc
214
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()));
|
||||
|
|
|
|||
29
textual.cc
29
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;
|
||||
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)
|
||||
|
|
|
|||
96
valexpr.cc
96
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.
|
||||
|
||||
#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]));
|
||||
|
|
|
|||
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;
|
||||
}
|
||||
|
||||
#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
|
||||
|
|
|
|||
2
walk.cc
2
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;
|
||||
|
|
|
|||
20
walk.h
20
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);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue