177 lines
3.3 KiB
C++
177 lines
3.3 KiB
C++
#ifndef _EXPR_H
|
|
#define _EXPR_H
|
|
|
|
#include "ledger.h"
|
|
#include "balance.h"
|
|
#include "item.h"
|
|
|
|
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
|
|
{
|
|
enum kind_t {
|
|
// Constants
|
|
CONSTANT_A,
|
|
CONSTANT_T,
|
|
|
|
// Item details
|
|
AMOUNT,
|
|
COST,
|
|
DATE,
|
|
CLEARED,
|
|
REAL,
|
|
INDEX,
|
|
|
|
// Item totals
|
|
BALANCE,
|
|
COST_BALANCE,
|
|
TOTAL,
|
|
COST_TOTAL,
|
|
|
|
// Functions
|
|
F_ARITH_MEAN,
|
|
F_VALUE,
|
|
F_NEG,
|
|
F_ABS,
|
|
F_PAYEE_MASK,
|
|
F_ACCOUNT_MASK,
|
|
|
|
// Binary operators
|
|
O_ADD,
|
|
O_SUB,
|
|
O_MUL,
|
|
O_DIV,
|
|
O_EQ,
|
|
O_LT,
|
|
O_LTE,
|
|
O_GT,
|
|
O_GTE,
|
|
O_NOT,
|
|
O_AND,
|
|
O_OR,
|
|
O_QUES,
|
|
O_COL,
|
|
|
|
LAST
|
|
};
|
|
|
|
kind_t type;
|
|
node_t * left;
|
|
node_t * right;
|
|
|
|
amount_t constant_a;
|
|
std::time_t constant_t;
|
|
mask_t * mask;
|
|
|
|
node_t(const kind_t _type)
|
|
: type(_type), left(NULL), right(NULL), mask(NULL) {}
|
|
|
|
~node_t() {
|
|
if (mask) delete mask;
|
|
if (left) delete left;
|
|
if (right) delete right;
|
|
}
|
|
|
|
balance_t compute(const item_t * item) const;
|
|
};
|
|
|
|
node_t * parse_expr(std::istream& in);
|
|
|
|
inline node_t * parse_expr(const char * p) {
|
|
std::istringstream stream(p);
|
|
return parse_expr(stream);
|
|
}
|
|
|
|
inline node_t * parse_expr(const std::string& str) {
|
|
return parse_expr(str.c_str());
|
|
}
|
|
|
|
inline node_t * find_node(node_t * node, node_t::kind_t type) {
|
|
node_t * result = NULL;
|
|
if (node->type == type)
|
|
result = node;
|
|
if (! result && node->left)
|
|
result = find_node(node->left, type);
|
|
if (! result && node->right)
|
|
result = find_node(node->right, type);
|
|
return result;
|
|
}
|
|
|
|
void dump_tree(std::ostream& out, node_t * node);
|
|
|
|
class value_predicate
|
|
{
|
|
public:
|
|
const node_t * predicate;
|
|
|
|
explicit value_predicate(const node_t * _predicate)
|
|
: predicate(_predicate) {}
|
|
|
|
bool operator ()(const transaction_t * xact) const {
|
|
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 operator ()(const entry_t * entry) const {
|
|
if (! predicate) {
|
|
return true;
|
|
} else {
|
|
item_t temp;
|
|
temp.date = entry->date;
|
|
temp.payee = entry->payee;
|
|
|
|
// Although there may be conflicting account masks for the whole
|
|
// set of transactions -- for example, /rent/&!/expenses/, which
|
|
// 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);
|
|
}
|
|
};
|
|
|
|
} // namespace report
|
|
|
|
#endif // _REPORT_H
|