1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
|
#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
|