predicate are now used instead of constraints
This commit is contained in:
parent
94e76ae87e
commit
493694f848
10 changed files with 343 additions and 446 deletions
3
Makefile
3
Makefile
|
|
@ -1,6 +1,5 @@
|
||||||
CODE = amount.cc balance.cc account.cc ledger.cc \
|
CODE = amount.cc balance.cc account.cc ledger.cc \
|
||||||
constraint.cc item.cc expr.cc format.cc \
|
item.cc expr.cc format.cc textual.cc binary.cc
|
||||||
textual.cc binary.cc
|
|
||||||
OBJS = $(patsubst %.cc,%.o,$(CODE))
|
OBJS = $(patsubst %.cc,%.o,$(CODE))
|
||||||
#CXX = cc
|
#CXX = cc
|
||||||
CXX = g++
|
CXX = g++
|
||||||
|
|
|
||||||
229
constraint.cc
229
constraint.cc
|
|
@ -1,229 +0,0 @@
|
||||||
#include "constraint.h"
|
|
||||||
#include "expr.h"
|
|
||||||
|
|
||||||
#include <pcre.h>
|
|
||||||
|
|
||||||
namespace ledger {
|
|
||||||
|
|
||||||
constraints_t::~constraints_t()
|
|
||||||
{
|
|
||||||
if (predicate) delete predicate;
|
|
||||||
if (sort_order) delete sort_order;
|
|
||||||
}
|
|
||||||
|
|
||||||
mask_t::mask_t(const std::string& pat) : exclude(false)
|
|
||||||
{
|
|
||||||
const char * p = pat.c_str();
|
|
||||||
if (*p == '-') {
|
|
||||||
exclude = true;
|
|
||||||
p++;
|
|
||||||
while (std::isspace(*p))
|
|
||||||
p++;
|
|
||||||
}
|
|
||||||
else if (*p == '+') {
|
|
||||||
p++;
|
|
||||||
while (std::isspace(*p))
|
|
||||||
p++;
|
|
||||||
}
|
|
||||||
pattern = p;
|
|
||||||
|
|
||||||
const char *error;
|
|
||||||
int erroffset;
|
|
||||||
regexp = pcre_compile(pattern.c_str(), PCRE_CASELESS,
|
|
||||||
&error, &erroffset, NULL);
|
|
||||||
if (! regexp)
|
|
||||||
std::cerr << "Warning: Failed to compile regexp: " << pattern
|
|
||||||
<< std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
mask_t::mask_t(const mask_t& m) : exclude(m.exclude), pattern(m.pattern)
|
|
||||||
{
|
|
||||||
const char *error;
|
|
||||||
int erroffset;
|
|
||||||
regexp = pcre_compile(pattern.c_str(), PCRE_CASELESS,
|
|
||||||
&error, &erroffset, NULL);
|
|
||||||
assert(regexp);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool mask_t::match(const std::string& str) const
|
|
||||||
{
|
|
||||||
static int ovec[30];
|
|
||||||
int result = pcre_exec((pcre *)regexp, NULL,
|
|
||||||
str.c_str(), str.length(), 0, 0, ovec, 30);
|
|
||||||
return result >= 0 && ! exclude;
|
|
||||||
}
|
|
||||||
|
|
||||||
mask_t::~mask_t() {
|
|
||||||
pcre_free((pcre *)regexp);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool matches(const masks_list& regexps, const std::string& str,
|
|
||||||
bool * by_exclusion)
|
|
||||||
{
|
|
||||||
if (regexps.empty())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
bool match = false;
|
|
||||||
bool definite = false;
|
|
||||||
|
|
||||||
for (masks_list::const_iterator r = regexps.begin();
|
|
||||||
r != regexps.end();
|
|
||||||
r++) {
|
|
||||||
static int ovec[30];
|
|
||||||
int result = pcre_exec((pcre *)(*r).regexp, NULL,
|
|
||||||
str.c_str(), str.length(), 0, 0, ovec, 30);
|
|
||||||
if (result >= 0) {
|
|
||||||
match = ! (*r).exclude;
|
|
||||||
definite = true;
|
|
||||||
}
|
|
||||||
else if ((*r).exclude) {
|
|
||||||
if (! match)
|
|
||||||
match = ! definite;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
definite = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (by_exclusion)
|
|
||||||
*by_exclusion = match && ! definite && by_exclusion;
|
|
||||||
|
|
||||||
return match;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool constraints_t::matches_date_range(const std::time_t date) const
|
|
||||||
{
|
|
||||||
if (begin_date != -1 && difftime(date, begin_date) < 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (end_date != -1 && difftime(date, end_date) >= 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (have_date_mask) {
|
|
||||||
struct std::tm * then = std::gmtime(&date);
|
|
||||||
|
|
||||||
if (date_mask.tm_mon != -1 &&
|
|
||||||
date_mask.tm_mon != then->tm_mon)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (date_mask.tm_mday != -1 &&
|
|
||||||
date_mask.tm_mday != then->tm_mday)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
// jww (2003-10-10): This causes only certain days of the week to
|
|
||||||
// print, even when it was not included in the mask.
|
|
||||||
if (date_mask.tm_wday != -1 &&
|
|
||||||
date_mask.tm_wday != then->tm_wday)
|
|
||||||
return false;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (date_mask.tm_year != -1 &&
|
|
||||||
date_mask.tm_year != then->tm_year)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool constraints_t::operator ()(const transaction_t * xact) const
|
|
||||||
{
|
|
||||||
if ((cleared_only && xact->entry->state != entry_t::CLEARED) ||
|
|
||||||
(uncleared_only && xact->entry->state == entry_t::CLEARED) ||
|
|
||||||
! matches_date_range(xact->entry->date))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (! payee_masks.empty() &&
|
|
||||||
(! (matches(payee_masks, xact->entry->payee)
|
|
||||||
//|| matches(payee_masks, xact->entry->code))
|
|
||||||
)))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (real_only && xact->flags & TRANSACTION_VIRTUAL)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (! account_masks.empty() &&
|
|
||||||
! (matches(account_masks, std::string(*(xact->account)))
|
|
||||||
//|| matches(account_masks, (*i)->note)
|
|
||||||
))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool constraints_t::operator ()(const entry_t * entry) const
|
|
||||||
{
|
|
||||||
if ((cleared_only && entry->state != entry_t::CLEARED) ||
|
|
||||||
(uncleared_only && entry->state == entry_t::CLEARED) ||
|
|
||||||
! matches_date_range(entry->date))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (! payee_masks.empty() &&
|
|
||||||
(! (matches(payee_masks, entry->payee)
|
|
||||||
//|| matches(payee_masks, entry->code)
|
|
||||||
)))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (! account_masks.empty()) {
|
|
||||||
bool match = false;
|
|
||||||
|
|
||||||
for (transactions_list::const_iterator i = entry->transactions.begin();
|
|
||||||
i != entry->transactions.end();
|
|
||||||
i++) {
|
|
||||||
if (real_only && (*i)->flags & TRANSACTION_VIRTUAL)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (matches(account_masks, std::string(*((*i)->account)))
|
|
||||||
//|| matches(account_masks, (*i)->note)
|
|
||||||
) {
|
|
||||||
match = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (! match)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool constraints_t::operator ()(const item_t * item) const
|
|
||||||
{
|
|
||||||
if (predicate && ! predicate->compute(item, begin(), end()))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (! matches_date_range(item->date))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (! payee_masks.empty() && ! matches(payee_masks, item->payee))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
// jww (2004-07-26): It shouldn't be necessary to check against the
|
|
||||||
// account here, since this is always done during initial compiling
|
|
||||||
// of the item_t tree.
|
|
||||||
|
|
||||||
if (! account_masks.empty()) {
|
|
||||||
bool match = false;
|
|
||||||
|
|
||||||
for (amounts_map::const_iterator i = item->value.quantity.amounts.begin();
|
|
||||||
i != item->value.quantity.amounts.end();
|
|
||||||
i++) {
|
|
||||||
if (matches(account_masks, std::string(*((*i)->account)))
|
|
||||||
//|| matches(account_masks, (*i)->note)
|
|
||||||
) {
|
|
||||||
match = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (! match)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace ledger
|
|
||||||
106
constraint.h
106
constraint.h
|
|
@ -2,6 +2,7 @@
|
||||||
#define _CONSTRAINT_H
|
#define _CONSTRAINT_H
|
||||||
|
|
||||||
#include "ledger.h"
|
#include "ledger.h"
|
||||||
|
#include "expr.h"
|
||||||
#include "item.h"
|
#include "item.h"
|
||||||
|
|
||||||
template <typename ForwardIterator, typename ValueType, typename Constraint>
|
template <typename ForwardIterator, typename ValueType, typename Constraint>
|
||||||
|
|
@ -60,96 +61,71 @@ class constrained_iterator
|
||||||
|
|
||||||
namespace ledger {
|
namespace ledger {
|
||||||
|
|
||||||
class mask_t
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
bool exclude;
|
|
||||||
std::string pattern;
|
|
||||||
void * regexp;
|
|
||||||
|
|
||||||
explicit mask_t(const std::string& pattern);
|
|
||||||
mask_t(const mask_t&);
|
|
||||||
|
|
||||||
~mask_t();
|
|
||||||
|
|
||||||
bool match(const std::string& str) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef std::list<mask_t> masks_list;
|
|
||||||
|
|
||||||
bool matches(const masks_list& regexps, const std::string& str,
|
|
||||||
bool * by_exclusion = NULL);
|
|
||||||
|
|
||||||
|
|
||||||
struct node_t;
|
|
||||||
|
|
||||||
enum periodicity_t {
|
|
||||||
PERIOD_NONE,
|
|
||||||
PERIOD_MONTHLY,
|
|
||||||
PERIOD_WEEKLY_SUN,
|
|
||||||
PERIOD_WEEKLY_MON
|
|
||||||
};
|
|
||||||
|
|
||||||
class constraints_t
|
class constraints_t
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
bool real_only;
|
|
||||||
bool cleared_only;
|
|
||||||
bool uncleared_only;
|
|
||||||
|
|
||||||
bool show_expanded;
|
bool show_expanded;
|
||||||
bool show_related;
|
bool show_related;
|
||||||
bool show_inverted;
|
bool show_inverted;
|
||||||
bool show_subtotals;
|
bool show_subtotals;
|
||||||
bool show_empty;
|
bool show_empty;
|
||||||
|
|
||||||
std::time_t begin_date;
|
node_t * predicate;
|
||||||
std::time_t end_date;
|
|
||||||
struct std::tm date_mask;
|
|
||||||
bool have_date_mask;
|
|
||||||
|
|
||||||
masks_list payee_masks;
|
|
||||||
masks_list account_masks;
|
|
||||||
|
|
||||||
periodicity_t period;
|
|
||||||
node_t * predicate;
|
|
||||||
node_t * sort_order;
|
|
||||||
|
|
||||||
explicit constraints_t() {
|
explicit constraints_t() {
|
||||||
real_only = false;
|
|
||||||
cleared_only = false;
|
|
||||||
uncleared_only = false;
|
|
||||||
|
|
||||||
show_expanded = false;
|
show_expanded = false;
|
||||||
show_related = false;
|
show_related = false;
|
||||||
show_inverted = false;
|
show_inverted = false;
|
||||||
show_subtotals = true;
|
show_subtotals = true;
|
||||||
show_empty = false;
|
show_empty = false;
|
||||||
|
|
||||||
begin_date = -1;
|
|
||||||
end_date = -1;
|
|
||||||
have_date_mask = false;
|
|
||||||
|
|
||||||
period = PERIOD_NONE;
|
|
||||||
predicate = NULL;
|
predicate = NULL;
|
||||||
sort_order = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
~constraints_t();
|
~constraints_t() {
|
||||||
|
if (predicate) delete predicate;
|
||||||
std::time_t begin() const {
|
|
||||||
return begin_date == -1 ? 0 : begin_date;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::time_t end() const {
|
bool operator ()(const transaction_t * xact) const {
|
||||||
return end_date == -1 ? std::time(NULL) : end_date;
|
if (! predicate) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
item_t temp;
|
||||||
|
temp.date = xact->entry->date;
|
||||||
|
temp.payee = xact->entry->payee;
|
||||||
|
temp.account = xact->account;
|
||||||
|
return predicate->compute(&temp);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool matches_date_range(const std::time_t date) const;
|
bool operator ()(const entry_t * entry) const {
|
||||||
|
if (! predicate) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
item_t temp;
|
||||||
|
temp.date = entry->date;
|
||||||
|
temp.payee = entry->payee;
|
||||||
|
|
||||||
bool operator ()(const transaction_t * xact) const;
|
// Although there may be conflicting account masks for the whole
|
||||||
bool operator ()(const entry_t * entry) const;
|
// set of transactions -- for example, /rent/&!/expenses/, which
|
||||||
bool operator ()(const item_t * item) const;
|
// might match one by not another transactions -- we let the
|
||||||
|
// entry through if at least one of the transactions meets the
|
||||||
|
// criterion
|
||||||
|
|
||||||
|
for (transactions_list::const_iterator i = entry->transactions.begin();
|
||||||
|
i != entry->transactions.end();
|
||||||
|
i++) {
|
||||||
|
temp.account = (*i)->account;
|
||||||
|
if (predicate->compute(&temp))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator ()(const item_t * item) const {
|
||||||
|
return ! predicate || predicate->compute(item);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef constrained_iterator<transactions_list::const_iterator, transaction_t *,
|
typedef constrained_iterator<transactions_list::const_iterator, transaction_t *,
|
||||||
|
|
|
||||||
169
expr.cc
169
expr.cc
|
|
@ -2,11 +2,95 @@
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
#include "textual.h"
|
#include "textual.h"
|
||||||
|
|
||||||
|
#include <pcre.h>
|
||||||
|
|
||||||
namespace ledger {
|
namespace ledger {
|
||||||
|
|
||||||
balance_t node_t::compute(const item_t * item,
|
mask_t::mask_t(const std::string& pat) : exclude(false)
|
||||||
const std::time_t begin,
|
{
|
||||||
const std::time_t end) const
|
const char * p = pat.c_str();
|
||||||
|
if (*p == '-') {
|
||||||
|
exclude = true;
|
||||||
|
p++;
|
||||||
|
while (std::isspace(*p))
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
else if (*p == '+') {
|
||||||
|
p++;
|
||||||
|
while (std::isspace(*p))
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
pattern = p;
|
||||||
|
|
||||||
|
const char *error;
|
||||||
|
int erroffset;
|
||||||
|
regexp = pcre_compile(pattern.c_str(), PCRE_CASELESS,
|
||||||
|
&error, &erroffset, NULL);
|
||||||
|
if (! regexp)
|
||||||
|
std::cerr << "Warning: Failed to compile regexp: " << pattern
|
||||||
|
<< std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
mask_t::mask_t(const mask_t& m) : exclude(m.exclude), pattern(m.pattern)
|
||||||
|
{
|
||||||
|
const char *error;
|
||||||
|
int erroffset;
|
||||||
|
regexp = pcre_compile(pattern.c_str(), PCRE_CASELESS,
|
||||||
|
&error, &erroffset, NULL);
|
||||||
|
assert(regexp);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool mask_t::match(const std::string& str) const
|
||||||
|
{
|
||||||
|
static int ovec[30];
|
||||||
|
int result = pcre_exec((pcre *)regexp, NULL,
|
||||||
|
str.c_str(), str.length(), 0, 0, ovec, 30);
|
||||||
|
return result >= 0 && ! exclude;
|
||||||
|
}
|
||||||
|
|
||||||
|
mask_t::~mask_t() {
|
||||||
|
pcre_free((pcre *)regexp);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
|
||||||
|
bool matches(const masks_list& regexps, const std::string& str,
|
||||||
|
bool * by_exclusion)
|
||||||
|
{
|
||||||
|
if (regexps.empty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
bool match = false;
|
||||||
|
bool definite = false;
|
||||||
|
|
||||||
|
for (masks_list::const_iterator r = regexps.begin();
|
||||||
|
r != regexps.end();
|
||||||
|
r++) {
|
||||||
|
static int ovec[30];
|
||||||
|
int result = pcre_exec((pcre *)(*r).regexp, NULL,
|
||||||
|
str.c_str(), str.length(), 0, 0, ovec, 30);
|
||||||
|
if (result >= 0) {
|
||||||
|
match = ! (*r).exclude;
|
||||||
|
definite = true;
|
||||||
|
}
|
||||||
|
else if ((*r).exclude) {
|
||||||
|
if (! match)
|
||||||
|
match = ! definite;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
definite = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (by_exclusion)
|
||||||
|
*by_exclusion = match && ! definite && by_exclusion;
|
||||||
|
|
||||||
|
return match;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
balance_t node_t::compute(const item_t * item) const
|
||||||
{
|
{
|
||||||
balance_t temp;
|
balance_t temp;
|
||||||
|
|
||||||
|
|
@ -44,35 +128,44 @@ balance_t node_t::compute(const item_t * item,
|
||||||
temp = amount_t((unsigned int) item->date);
|
temp = amount_t((unsigned int) item->date);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case CLEARED:
|
||||||
|
#if 0
|
||||||
|
temp = amount_t(item->state == CLEARED ? 1 : 0);
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
|
||||||
|
case REAL:
|
||||||
|
#if 0
|
||||||
|
temp = amount_t(item->flags & TRANSACTION_VIRTUAL ? 0 : 1);
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
|
||||||
case INDEX:
|
case INDEX:
|
||||||
temp = amount_t(item->index + 1);
|
temp = amount_t(item->index + 1);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BEGIN_DATE:
|
|
||||||
temp = amount_t((unsigned int) begin);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case END_DATE:
|
|
||||||
temp = amount_t((unsigned int) end);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case F_ARITH_MEAN:
|
case F_ARITH_MEAN:
|
||||||
assert(left);
|
assert(left);
|
||||||
temp = left->compute(item, begin, end);
|
temp = left->compute(item);
|
||||||
temp /= amount_t(item->index + 1);
|
temp /= amount_t(item->index + 1);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case F_NEG:
|
case F_NEG:
|
||||||
assert(left);
|
assert(left);
|
||||||
temp = left->compute(item, begin, end).negated();
|
temp = left->compute(item).negated();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case F_ABS:
|
case F_ABS:
|
||||||
assert(left);
|
assert(left);
|
||||||
temp = abs(left->compute(item, begin, end));
|
temp = abs(left->compute(item));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case F_REGEXP:
|
case F_PAYEE_MASK:
|
||||||
|
assert(mask);
|
||||||
|
temp = mask->match(item->payee);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case F_ACCOUNT_MASK:
|
||||||
assert(mask);
|
assert(mask);
|
||||||
temp = (item->account &&
|
temp = (item->account &&
|
||||||
mask->match(item->account->fullname())) ? 1 : 0;
|
mask->match(item->account->fullname())) ? 1 : 0;
|
||||||
|
|
@ -80,14 +173,12 @@ balance_t node_t::compute(const item_t * item,
|
||||||
|
|
||||||
case F_VALUE: {
|
case F_VALUE: {
|
||||||
assert(left);
|
assert(left);
|
||||||
temp = left->compute(item, begin, end);
|
temp = left->compute(item);
|
||||||
|
|
||||||
std::time_t moment = -1;
|
std::time_t moment = -1;
|
||||||
if (right) {
|
if (right) {
|
||||||
switch (right->type) {
|
switch (right->type) {
|
||||||
case DATE: moment = item->date; break;
|
case DATE: moment = item->date; break;
|
||||||
case BEGIN_DATE: moment = begin; break;
|
|
||||||
case END_DATE: moment = end; break;
|
|
||||||
default:
|
default:
|
||||||
throw compute_error("Invalid date passed to P(v,d)");
|
throw compute_error("Invalid date passed to P(v,d)");
|
||||||
}
|
}
|
||||||
|
|
@ -97,15 +188,15 @@ balance_t node_t::compute(const item_t * item,
|
||||||
}
|
}
|
||||||
|
|
||||||
case O_NOT:
|
case O_NOT:
|
||||||
temp = left->compute(item, begin, end) ? 0 : 1;
|
temp = left->compute(item) ? 0 : 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case O_QUES:
|
case O_QUES:
|
||||||
temp = left->compute(item, begin, end);
|
temp = left->compute(item);
|
||||||
if (temp)
|
if (temp)
|
||||||
temp = right->left->compute(item, begin, end);
|
temp = right->left->compute(item);
|
||||||
else
|
else
|
||||||
temp = right->right->compute(item, begin, end);
|
temp = right->right->compute(item);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case O_AND:
|
case O_AND:
|
||||||
|
|
@ -121,8 +212,8 @@ balance_t node_t::compute(const item_t * item,
|
||||||
case O_DIV: {
|
case O_DIV: {
|
||||||
assert(left);
|
assert(left);
|
||||||
assert(right);
|
assert(right);
|
||||||
balance_t left_bal = left->compute(item, begin, end);
|
balance_t left_bal = left->compute(item);
|
||||||
balance_t right_bal = right->compute(item, begin, end);
|
balance_t right_bal = right->compute(item);
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case O_AND: temp = (left_bal && right_bal) ? 1 : 0; break;
|
case O_AND: temp = (left_bal && right_bal) ? 1 : 0; break;
|
||||||
case O_OR: temp = (left_bal || right_bal) ? 1 : 0; break;
|
case O_OR: temp = (left_bal || right_bal) ? 1 : 0; break;
|
||||||
|
|
@ -197,8 +288,8 @@ node_t * parse_term(std::istream& in)
|
||||||
case 'a': node = new node_t(node_t::AMOUNT); break;
|
case 'a': node = new node_t(node_t::AMOUNT); break;
|
||||||
case 'c': node = new node_t(node_t::COST); break;
|
case 'c': node = new node_t(node_t::COST); break;
|
||||||
case 'd': node = new node_t(node_t::DATE); break;
|
case 'd': node = new node_t(node_t::DATE); break;
|
||||||
case 'b': node = new node_t(node_t::BEGIN_DATE); break;
|
case 'X': node = new node_t(node_t::CLEARED); break;
|
||||||
case 'e': node = new node_t(node_t::END_DATE); break;
|
case 'R': node = new node_t(node_t::REAL); break;
|
||||||
case 'i': node = new node_t(node_t::INDEX); break;
|
case 'i': node = new node_t(node_t::INDEX); break;
|
||||||
case 'B': node = new node_t(node_t::BALANCE); break;
|
case 'B': node = new node_t(node_t::BALANCE); break;
|
||||||
case 'T': node = new node_t(node_t::TOTAL); break;
|
case 'T': node = new node_t(node_t::TOTAL); break;
|
||||||
|
|
@ -256,8 +347,15 @@ node_t * parse_term(std::istream& in)
|
||||||
// Other
|
// Other
|
||||||
case '/': {
|
case '/': {
|
||||||
std::string ident;
|
std::string ident;
|
||||||
|
bool payee_mask = false;
|
||||||
|
|
||||||
c = in.peek();
|
c = in.peek();
|
||||||
|
if (c == '/') {
|
||||||
|
payee_mask = true;
|
||||||
|
in.get(c);
|
||||||
|
c = in.peek();
|
||||||
|
}
|
||||||
|
|
||||||
while (! in.eof() && c != '/') {
|
while (! in.eof() && c != '/') {
|
||||||
in.get(c);
|
in.get(c);
|
||||||
if (c == '\\')
|
if (c == '\\')
|
||||||
|
|
@ -265,9 +363,11 @@ node_t * parse_term(std::istream& in)
|
||||||
ident += c;
|
ident += c;
|
||||||
c = in.peek();
|
c = in.peek();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (c == '/') {
|
if (c == '/') {
|
||||||
in.get(c);
|
in.get(c);
|
||||||
node = new node_t(node_t::F_REGEXP);
|
node = new node_t(payee_mask ?
|
||||||
|
node_t::F_PAYEE_MASK : node_t::F_ACCOUNT_MASK);
|
||||||
node->mask = new mask_t(ident);
|
node->mask = new mask_t(ident);
|
||||||
} else {
|
} else {
|
||||||
throw expr_error("Missing closing '/'");
|
throw expr_error("Missing closing '/'");
|
||||||
|
|
@ -517,13 +617,13 @@ static void dump_tree(std::ostream& out, node_t * node)
|
||||||
case node_t::AMOUNT: out << "AMOUNT"; break;
|
case node_t::AMOUNT: out << "AMOUNT"; break;
|
||||||
case node_t::COST: out << "COST"; break;
|
case node_t::COST: out << "COST"; break;
|
||||||
case node_t::DATE: out << "DATE"; break;
|
case node_t::DATE: out << "DATE"; break;
|
||||||
|
case node_t::CLEARED: out << "CLEARED"; break;
|
||||||
|
case node_t::REAL: out << "REAL"; break;
|
||||||
case node_t::INDEX: out << "INDEX"; break;
|
case node_t::INDEX: out << "INDEX"; break;
|
||||||
case node_t::BALANCE: out << "BALANCE"; break;
|
case node_t::BALANCE: out << "BALANCE"; break;
|
||||||
case node_t::COST_BALANCE: out << "COST_BALANCE"; break;
|
case node_t::COST_BALANCE: out << "COST_BALANCE"; break;
|
||||||
case node_t::TOTAL: out << "TOTAL"; break;
|
case node_t::TOTAL: out << "TOTAL"; break;
|
||||||
case node_t::COST_TOTAL: out << "COST_TOTAL"; break;
|
case node_t::COST_TOTAL: out << "COST_TOTAL"; break;
|
||||||
case node_t::BEGIN_DATE: out << "BEGIN"; break;
|
|
||||||
case node_t::END_DATE: out << "END"; break;
|
|
||||||
|
|
||||||
case node_t::F_ARITH_MEAN:
|
case node_t::F_ARITH_MEAN:
|
||||||
out << "MEAN(";
|
out << "MEAN(";
|
||||||
|
|
@ -543,9 +643,14 @@ static void dump_tree(std::ostream& out, node_t * node)
|
||||||
out << ")";
|
out << ")";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case node_t::F_REGEXP:
|
case node_t::F_PAYEE_MASK:
|
||||||
assert(node->mask);
|
assert(node->mask);
|
||||||
out << "RE(" << node->mask->pattern << ")";
|
out << "P_MASK(" << node->mask->pattern << ")";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case node_t::F_ACCOUNT_MASK:
|
||||||
|
assert(node->mask);
|
||||||
|
out << "A_MASK(" << node->mask->pattern << ")";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case node_t::F_VALUE:
|
case node_t::F_VALUE:
|
||||||
|
|
|
||||||
38
expr.h
38
expr.h
|
|
@ -3,10 +3,33 @@
|
||||||
|
|
||||||
#include "ledger.h"
|
#include "ledger.h"
|
||||||
#include "balance.h"
|
#include "balance.h"
|
||||||
#include "constraint.h"
|
#include "item.h"
|
||||||
|
|
||||||
namespace ledger {
|
namespace ledger {
|
||||||
|
|
||||||
|
class mask_t
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
bool exclude;
|
||||||
|
std::string pattern;
|
||||||
|
void * regexp;
|
||||||
|
|
||||||
|
explicit mask_t(const std::string& pattern);
|
||||||
|
mask_t(const mask_t&);
|
||||||
|
|
||||||
|
~mask_t();
|
||||||
|
|
||||||
|
bool match(const std::string& str) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
typedef std::list<mask_t> masks_list;
|
||||||
|
|
||||||
|
bool matches(const masks_list& regexps, const std::string& str,
|
||||||
|
bool * by_exclusion = NULL);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
struct node_t
|
struct node_t
|
||||||
{
|
{
|
||||||
enum kind_t {
|
enum kind_t {
|
||||||
|
|
@ -18,6 +41,8 @@ struct node_t
|
||||||
AMOUNT,
|
AMOUNT,
|
||||||
COST,
|
COST,
|
||||||
DATE,
|
DATE,
|
||||||
|
CLEARED,
|
||||||
|
REAL,
|
||||||
INDEX,
|
INDEX,
|
||||||
|
|
||||||
// Item totals
|
// Item totals
|
||||||
|
|
@ -26,16 +51,13 @@ struct node_t
|
||||||
TOTAL,
|
TOTAL,
|
||||||
COST_TOTAL,
|
COST_TOTAL,
|
||||||
|
|
||||||
// Constraint details
|
|
||||||
BEGIN_DATE,
|
|
||||||
END_DATE,
|
|
||||||
|
|
||||||
// Functions
|
// Functions
|
||||||
F_ARITH_MEAN,
|
F_ARITH_MEAN,
|
||||||
F_VALUE,
|
F_VALUE,
|
||||||
F_NEG,
|
F_NEG,
|
||||||
F_ABS,
|
F_ABS,
|
||||||
F_REGEXP,
|
F_PAYEE_MASK,
|
||||||
|
F_ACCOUNT_MASK,
|
||||||
|
|
||||||
// Binary operators
|
// Binary operators
|
||||||
O_ADD,
|
O_ADD,
|
||||||
|
|
@ -73,9 +95,7 @@ struct node_t
|
||||||
if (right) delete right;
|
if (right) delete right;
|
||||||
}
|
}
|
||||||
|
|
||||||
balance_t compute(const item_t * item,
|
balance_t compute(const item_t * item) const;
|
||||||
const std::time_t begin = -1,
|
|
||||||
const std::time_t end = -1) const;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
node_t * parse_expr(std::istream& in);
|
node_t * parse_expr(std::istream& in);
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,7 @@ std::string truncated(const std::string& str, unsigned int width)
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string maximal_account_name(const item_t * item,
|
std::string maximal_account_name(const item_t * item, const item_t * parent)
|
||||||
const item_t * parent)
|
|
||||||
{
|
{
|
||||||
std::string name = item->account->name;
|
std::string name = item->account->name;
|
||||||
for (const item_t * i = item->parent;
|
for (const item_t * i = item->parent;
|
||||||
|
|
|
||||||
29
format.h
29
format.h
|
|
@ -63,37 +63,12 @@ struct format_t
|
||||||
void format_elements(std::ostream& out, const item_t * item,
|
void format_elements(std::ostream& out, const item_t * item,
|
||||||
const item_t * displayed_parent = NULL) const;
|
const item_t * displayed_parent = NULL) const;
|
||||||
|
|
||||||
#if 1
|
|
||||||
static balance_t compute_value(const item_t * item) {
|
static balance_t compute_value(const item_t * item) {
|
||||||
if (value_expr)
|
return value_expr ? value_expr->compute(item) : balance_t();
|
||||||
return value_expr->compute(item);
|
|
||||||
else
|
|
||||||
return balance_t();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static balance_t compute_total(const item_t * item) {
|
static balance_t compute_total(const item_t * item) {
|
||||||
if (total_expr)
|
return total_expr ? total_expr->compute(item) : balance_t();
|
||||||
return total_expr->compute(item);
|
|
||||||
else
|
|
||||||
return balance_t();
|
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
static balance_t compute_value(const item_t * item,
|
|
||||||
const constraints_t& constraints) {
|
|
||||||
if (value_expr)
|
|
||||||
return value_expr->compute(item, constraints.begin(), constraints.end());
|
|
||||||
else
|
|
||||||
return balance_t();
|
|
||||||
}
|
|
||||||
|
|
||||||
static balance_t compute_total(const item_t * item,
|
|
||||||
const constraints_t& constraints) {
|
|
||||||
if (total_expr)
|
|
||||||
return total_expr->compute(item, constraints.begin(), constraints.end());
|
|
||||||
else
|
|
||||||
return balance_t();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ledger
|
} // namespace ledger
|
||||||
|
|
|
||||||
1
item.cc
1
item.cc
|
|
@ -12,7 +12,6 @@ item_t * walk_accounts(const account_t * account,
|
||||||
{
|
{
|
||||||
item_t * item = new item_t;
|
item_t * item = new item_t;
|
||||||
item->account = account;
|
item->account = account;
|
||||||
item->date = constraints.end() - 1;
|
|
||||||
|
|
||||||
for (constrained_transactions_list_const_iterator
|
for (constrained_transactions_list_const_iterator
|
||||||
i(account->transactions.begin(),
|
i(account->transactions.begin(),
|
||||||
|
|
|
||||||
209
main.cc
209
main.cc
|
|
@ -23,53 +23,54 @@ namespace ledger {
|
||||||
|
|
||||||
static const std::string bal_fmt = "%20T%2_%-n\n";
|
static const std::string bal_fmt = "%20T%2_%-n\n";
|
||||||
|
|
||||||
void show_balances(std::ostream& out,
|
unsigned int show_balances(std::ostream& out,
|
||||||
items_deque& items,
|
items_deque& items,
|
||||||
const constraints_t& constraints,
|
const constraints_t& constraints,
|
||||||
const format_t& format,
|
const node_t * sort_order,
|
||||||
const item_t * displayed_parent)
|
const format_t& format,
|
||||||
|
const item_t * displayed_parent)
|
||||||
{
|
{
|
||||||
|
unsigned int headlines = 0;
|
||||||
|
|
||||||
for (items_deque::const_iterator i = items.begin();
|
for (items_deque::const_iterator i = items.begin();
|
||||||
i != items.end();
|
i != items.end();
|
||||||
i++) {
|
i++) {
|
||||||
const item_t * parent = displayed_parent;
|
const item_t * parent = displayed_parent;
|
||||||
|
|
||||||
bool by_exclusion = false;
|
if (constraints(*i) &&
|
||||||
std::string name = maximal_account_name(*i, parent);
|
|
||||||
const bool match = (constraints.show_expanded ||
|
|
||||||
(! constraints.account_masks.empty() &&
|
|
||||||
matches(constraints.account_masks, name,
|
|
||||||
&by_exclusion) &&
|
|
||||||
(! by_exclusion ||
|
|
||||||
displayed_parent->parent == NULL)) ||
|
|
||||||
(constraints.account_masks.empty() &&
|
|
||||||
displayed_parent->parent == NULL));
|
|
||||||
|
|
||||||
if (match && constraints(*i) &&
|
|
||||||
((*i)->subitems.size() != 1 ||
|
((*i)->subitems.size() != 1 ||
|
||||||
(*i)->total != (*i)->subitems[0]->total)) {
|
(*i)->total != (*i)->subitems[0]->total)) {
|
||||||
format.format_elements(out, *i, parent);
|
format.format_elements(out, *i, parent);
|
||||||
parent = *i;
|
parent = *i;
|
||||||
|
|
||||||
|
if (! displayed_parent->parent)
|
||||||
|
headlines++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (constraints.sort_order)
|
if (sort_order)
|
||||||
(*i)->sort(constraints.sort_order);
|
(*i)->sort(sort_order);
|
||||||
|
|
||||||
show_balances(out, (*i)->subitems, constraints, format, parent);
|
if (constraints.show_expanded)
|
||||||
|
headlines += show_balances(out, (*i)->subitems, constraints,
|
||||||
|
sort_order, format, parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return headlines;
|
||||||
}
|
}
|
||||||
|
|
||||||
void balance_report(std::ostream& out,
|
void balance_report(std::ostream& out,
|
||||||
item_t * top,
|
item_t * top,
|
||||||
const constraints_t& constraints,
|
const constraints_t& constraints,
|
||||||
const format_t& format)
|
const node_t * sort_order,
|
||||||
|
const format_t& format)
|
||||||
{
|
{
|
||||||
if (constraints.sort_order)
|
if (sort_order)
|
||||||
top->sort(constraints.sort_order);
|
top->sort(sort_order);
|
||||||
|
|
||||||
show_balances(out, top->subitems, constraints, format, top);
|
unsigned int headlines = show_balances(out, top->subitems, constraints,
|
||||||
|
sort_order, format, top);
|
||||||
|
|
||||||
if (constraints.show_subtotals && top->subitems.size() > 1 && top->total) {
|
if (constraints.show_subtotals && headlines > 1 && top->total) {
|
||||||
std::cout << "--------------------\n";
|
std::cout << "--------------------\n";
|
||||||
format.format_elements(std::cout, top);
|
format.format_elements(std::cout, top);
|
||||||
}
|
}
|
||||||
|
|
@ -127,11 +128,12 @@ static void report_value_change(std::ostream& out,
|
||||||
void register_report(std::ostream& out,
|
void register_report(std::ostream& out,
|
||||||
item_t * top,
|
item_t * top,
|
||||||
const constraints_t& constraints,
|
const constraints_t& constraints,
|
||||||
|
const node_t * sort_order,
|
||||||
const format_t& first_line_format,
|
const format_t& first_line_format,
|
||||||
const format_t& next_lines_format)
|
const format_t& next_lines_format)
|
||||||
{
|
{
|
||||||
if (constraints.sort_order)
|
if (sort_order)
|
||||||
top->sort(constraints.sort_order);
|
top->sort(sort_order);
|
||||||
|
|
||||||
balance_pair_t balance;
|
balance_pair_t balance;
|
||||||
balance_pair_t last_reported;
|
balance_pair_t last_reported;
|
||||||
|
|
@ -203,8 +205,8 @@ void register_report(std::ostream& out,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (show_commodities_revalued)
|
if (show_commodities_revalued)
|
||||||
report_value_change(out, constraints.end(), balance, last_reported,
|
report_value_change(out, -1, balance, last_reported, constraints,
|
||||||
constraints, first_line_format, next_lines_format);
|
first_line_format, next_lines_format);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -471,11 +473,17 @@ int main(int argc, char * argv[])
|
||||||
std::list<std::string> files;
|
std::list<std::string> files;
|
||||||
ledger::ledger_t * journal = new ledger::ledger_t;
|
ledger::ledger_t * journal = new ledger::ledger_t;
|
||||||
ledger::constraints_t constraints;
|
ledger::constraints_t constraints;
|
||||||
|
std::string predicate;
|
||||||
std::string format_string;
|
std::string format_string;
|
||||||
std::string sort_order;
|
std::string sort_str;
|
||||||
|
ledger::node_t * sort_order = NULL;
|
||||||
std::string value_expr = "a";
|
std::string value_expr = "a";
|
||||||
std::string total_expr = "T";
|
std::string total_expr = "T";
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
bool debug = false;
|
||||||
|
#endif
|
||||||
|
|
||||||
// Initialize some variables based on environment variable settings
|
// Initialize some variables based on environment variable settings
|
||||||
|
|
||||||
if (char * p = std::getenv("PRICE_HIST"))
|
if (char * p = std::getenv("PRICE_HIST"))
|
||||||
|
|
@ -518,13 +526,19 @@ int main(int argc, char * argv[])
|
||||||
int c, index;
|
int c, index;
|
||||||
while (-1 !=
|
while (-1 !=
|
||||||
(c = getopt(argc, argv,
|
(c = getopt(argc, argv,
|
||||||
"+a:ABb:Ccd:DEe:F:f:Ghi:L:l:MN:noOP:p:QRS:st:T:UVvWXZ"))) {
|
"+ABb:Ccd:DEe:F:f:Ghi:L:l:MnoOP:p:QRS:st:T:UVvWXZz"))) {
|
||||||
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':
|
||||||
std::cout
|
std::cout
|
||||||
<< "Ledger " << ledger::version
|
<< "Ledger " << ledger::version
|
||||||
|
|
@ -547,47 +561,49 @@ int main(int argc, char * argv[])
|
||||||
ledger::set_price_conversion(optarg);
|
ledger::set_price_conversion(optarg);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Constraint options
|
|
||||||
case 'a':
|
|
||||||
constraints.account_masks.push_back(ledger::mask_t(optarg));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'b':
|
case 'b':
|
||||||
if (! ledger::parse_date(optarg, &constraints.begin_date)) {
|
if (! predicate.empty())
|
||||||
std::cerr << "Error: Bad begin date: " << optarg << std::endl;
|
predicate += "&";
|
||||||
return 1;
|
predicate += "(d>=[";
|
||||||
}
|
predicate += optarg;
|
||||||
|
predicate += "])";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'e':
|
case 'e':
|
||||||
if (! ledger::parse_date(optarg, &constraints.end_date)) {
|
if (! predicate.empty())
|
||||||
std::cerr << "Error: Bad end date: " << optarg << std::endl;
|
predicate += "&";
|
||||||
return 1;
|
predicate += "(d<[";
|
||||||
}
|
predicate += optarg;
|
||||||
|
predicate += "])";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'c':
|
case 'c': {
|
||||||
constraints.end_date = std::time(NULL);
|
if (! predicate.empty())
|
||||||
break;
|
predicate += "&";
|
||||||
|
predicate += "(d<";
|
||||||
case 'd':
|
std::ostringstream now;
|
||||||
constraints.have_date_mask = true;
|
now << std::time(NULL);
|
||||||
if (! ledger::parse_date_mask(optarg, &constraints.date_mask)) {
|
predicate += now.str();
|
||||||
std::cerr << "Error: Bad date mask: " << optarg << std::endl;
|
predicate += ")";
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case 'C':
|
case 'C':
|
||||||
constraints.cleared_only = true;
|
if (! predicate.empty())
|
||||||
|
predicate += "&";
|
||||||
|
predicate += "X";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'U':
|
case 'U':
|
||||||
constraints.uncleared_only = true;
|
if (! predicate.empty())
|
||||||
|
predicate += "&";
|
||||||
|
predicate += "!X";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'R':
|
case 'R':
|
||||||
constraints.real_only = true;
|
if (! predicate.empty())
|
||||||
|
predicate += "&";
|
||||||
|
predicate += "R";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Customizing output
|
// Customizing output
|
||||||
|
|
@ -595,10 +611,6 @@ int main(int argc, char * argv[])
|
||||||
format_string = optarg;
|
format_string = optarg;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'M':
|
|
||||||
constraints.period = ledger::PERIOD_MONTHLY;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'E':
|
case 'E':
|
||||||
constraints.show_empty = true;
|
constraints.show_empty = true;
|
||||||
break;
|
break;
|
||||||
|
|
@ -612,7 +624,7 @@ int main(int argc, char * argv[])
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'S':
|
case 'S':
|
||||||
sort_order = optarg;
|
sort_str = optarg;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'o':
|
case 'o':
|
||||||
|
|
@ -620,7 +632,11 @@ int main(int argc, char * argv[])
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'l':
|
case 'l':
|
||||||
constraints.predicate = ledger::parse_expr(optarg);
|
if (! predicate.empty())
|
||||||
|
predicate += "&";
|
||||||
|
predicate += "(";
|
||||||
|
predicate += optarg;
|
||||||
|
predicate += ")";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Commodity reporting
|
// Commodity reporting
|
||||||
|
|
@ -761,17 +777,51 @@ int main(int argc, char * argv[])
|
||||||
index++;
|
index++;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
constraints.account_masks.push_back(ledger::mask_t(argv[index]));
|
|
||||||
|
constraints.show_expanded = true;
|
||||||
|
|
||||||
|
if (! predicate.empty())
|
||||||
|
predicate += "&";
|
||||||
|
|
||||||
|
if (argv[index][0] == '-') {
|
||||||
|
predicate += "(!/";
|
||||||
|
predicate += argv[index] + 1;
|
||||||
|
} else {
|
||||||
|
predicate += "(/";
|
||||||
|
predicate += argv[index];
|
||||||
|
}
|
||||||
|
predicate += "/)";
|
||||||
}
|
}
|
||||||
|
|
||||||
for (; index < argc; index++)
|
for (; index < argc; index++) {
|
||||||
constraints.payee_masks.push_back(ledger::mask_t(argv[index]));
|
constraints.show_expanded = true;
|
||||||
|
|
||||||
|
if (! predicate.empty())
|
||||||
|
predicate += "&";
|
||||||
|
|
||||||
|
if (argv[index][0] == '-') {
|
||||||
|
predicate += "(!//";
|
||||||
|
predicate += argv[index] + 1;
|
||||||
|
} else {
|
||||||
|
predicate += "(//";
|
||||||
|
predicate += argv[index];
|
||||||
|
}
|
||||||
|
predicate += "/)";
|
||||||
|
}
|
||||||
|
|
||||||
// Copy the constraints to the format object, and compile the value
|
// Copy the constraints to the format object, and compile the value
|
||||||
// and total style strings
|
// and total style strings
|
||||||
|
|
||||||
if (! sort_order.empty())
|
if (! predicate.empty()) {
|
||||||
constraints.sort_order = ledger::parse_expr(sort_order);
|
#ifdef DEBUG
|
||||||
|
if (debug)
|
||||||
|
std::cerr << "predicate = " << predicate << std::endl;
|
||||||
|
#endif
|
||||||
|
constraints.predicate = ledger::parse_expr(predicate);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! sort_str.empty())
|
||||||
|
sort_order = ledger::parse_expr(sort_str);
|
||||||
|
|
||||||
// Setup the meaning of %t and %T encountered in format strings
|
// Setup the meaning of %t and %T encountered in format strings
|
||||||
|
|
||||||
|
|
@ -784,8 +834,7 @@ int main(int argc, char * argv[])
|
||||||
#if 0
|
#if 0
|
||||||
if (ledger::item_t * top
|
if (ledger::item_t * top
|
||||||
= ledger::walk_entries(journal->entries.begin(),
|
= ledger::walk_entries(journal->entries.begin(),
|
||||||
journal->entries.end(),
|
journal->entries.end(), constraints)) {
|
||||||
constraints)) {
|
|
||||||
ledger::format_t * format = new ledger::format_t(format_string);
|
ledger::format_t * format = new ledger::format_t(format_string);
|
||||||
ledger::entry_report(std::cout, top, *format);
|
ledger::entry_report(std::cout, top, *format);
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
|
|
@ -808,15 +857,14 @@ int main(int argc, char * argv[])
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
else if (constraints.period == ledger::PERIOD_NONE &&
|
else if (! sort_order && ! constraints.show_related &&
|
||||||
! constraints.sort_order && ! constraints.show_related &&
|
|
||||||
(command == "balance" || command == "bal")) {
|
(command == "balance" || command == "bal")) {
|
||||||
if (ledger::item_t * top
|
if (ledger::item_t * top
|
||||||
= ledger::walk_accounts(journal->master, constraints)) {
|
= ledger::walk_accounts(journal->master, constraints)) {
|
||||||
ledger::format_t * format
|
ledger::format_t * format
|
||||||
= new ledger::format_t(format_string.empty() ?
|
= new ledger::format_t(format_string.empty() ?
|
||||||
ledger::bal_fmt : format_string);
|
ledger::bal_fmt : format_string);
|
||||||
ledger::balance_report(std::cout, top, constraints, *format);
|
ledger::balance_report(std::cout, top, constraints, sort_order, *format);
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
delete format;
|
delete format;
|
||||||
delete top;
|
delete top;
|
||||||
|
|
@ -832,7 +880,8 @@ int main(int argc, char * argv[])
|
||||||
ledger::format_t * format
|
ledger::format_t * format
|
||||||
= new ledger::format_t(format_string.empty() ?
|
= new ledger::format_t(format_string.empty() ?
|
||||||
ledger::bal_fmt : format_string);
|
ledger::bal_fmt : format_string);
|
||||||
ledger::balance_report(std::cout, top, constraints, *format);
|
ledger::balance_report(std::cout, top, constraints, sort_order,
|
||||||
|
*format);
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
delete format;
|
delete format;
|
||||||
delete top;
|
delete top;
|
||||||
|
|
@ -862,7 +911,8 @@ int main(int argc, char * argv[])
|
||||||
|
|
||||||
ledger::format_t * format = new ledger::format_t(first_line_format);
|
ledger::format_t * format = new ledger::format_t(first_line_format);
|
||||||
ledger::format_t * nformat = new ledger::format_t(next_lines_format);
|
ledger::format_t * nformat = new ledger::format_t(next_lines_format);
|
||||||
ledger::register_report(std::cout, top, constraints, *format, *nformat);
|
ledger::register_report(std::cout, top, constraints, sort_order,
|
||||||
|
*format, *nformat);
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
delete format;
|
delete format;
|
||||||
delete top;
|
delete top;
|
||||||
|
|
@ -887,6 +937,9 @@ int main(int argc, char * argv[])
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
delete journal;
|
delete journal;
|
||||||
|
|
||||||
|
if (sort_order)
|
||||||
|
delete sort_order;
|
||||||
|
|
||||||
if (ledger::format_t::value_expr)
|
if (ledger::format_t::value_expr)
|
||||||
delete ledger::format_t::value_expr;
|
delete ledger::format_t::value_expr;
|
||||||
if (ledger::format_t::total_expr)
|
if (ledger::format_t::total_expr)
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue