Regular expressions are working again, such that very basic register reports
are now possible.
This commit is contained in:
parent
8a21391d0a
commit
bcffbc96ba
8 changed files with 159 additions and 594 deletions
413
format.cc
413
format.cc
|
|
@ -272,430 +272,33 @@ void format_t::format(std::ostream& out_str, scope_t& scope)
|
|||
try {
|
||||
elem->expr.compile(scope);
|
||||
|
||||
value_t value;
|
||||
if (elem->expr.is_function()) {
|
||||
call_scope_t args(scope);
|
||||
args.push_back(long(elem->max_width));
|
||||
elem->expr.get_function()(args).dump(out, elem->min_width);
|
||||
value = elem->expr.get_function()(args);
|
||||
} else {
|
||||
elem->expr.calc(scope).dump(out, elem->min_width);
|
||||
value = elem->expr.calc(scope);
|
||||
}
|
||||
value.strip_annotations().dump(out, elem->min_width);
|
||||
}
|
||||
catch (const calc_error&) {
|
||||
out << (string("%") + elem->chars);
|
||||
}
|
||||
break;
|
||||
|
||||
#if 0
|
||||
case element_t::ACCOUNT_FULLNAME:
|
||||
scope.resolve("account").dump(out, elem->min_width);
|
||||
break;
|
||||
case element_t::ACCOUNT_NAME:
|
||||
scope.resolve("account_base").dump(out, elem->min_width);
|
||||
break;
|
||||
|
||||
case element_t::AMOUNT:
|
||||
out << "a";
|
||||
//out << scope.resolve("amount");
|
||||
break;
|
||||
case element_t::TOTAL:
|
||||
out << "T";
|
||||
//out << scope.resolve("total");
|
||||
break;
|
||||
|
||||
case element_t::VALUE_EXPR: {
|
||||
expr_t * calc;
|
||||
switch (elem->type) {
|
||||
case element_t::AMOUNT:
|
||||
assert(value_expr::amount_expr.get());
|
||||
calc = value_expr::amount_expr.get();
|
||||
break;
|
||||
case element_t::TOTAL:
|
||||
assert(value_expr::total_expr.get());
|
||||
calc = value_expr::total_expr.get();
|
||||
break;
|
||||
case element_t::VALUE_EXPR:
|
||||
calc = const_cast<value_expr *>(&elem->val_expr);
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
if (! calc)
|
||||
break;
|
||||
|
||||
value_t value;
|
||||
const balance_t * bal = NULL;
|
||||
|
||||
calc->compute(value, details);
|
||||
|
||||
if (! amount_t::keep_price ||
|
||||
! amount_t::keep_date ||
|
||||
! amount_t::keep_tag) {
|
||||
switch (value.type()) {
|
||||
case value_t::AMOUNT:
|
||||
case value_t::BALANCE:
|
||||
case value_t::BALANCE_PAIR:
|
||||
value = value.strip_annotations();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool highlighted = false;
|
||||
|
||||
switch (value.type()) {
|
||||
case value_t::BOOLEAN:
|
||||
out << (value.as_boolean() ? "true" : "false");
|
||||
break;
|
||||
|
||||
case value_t::INTEGER:
|
||||
if (ansi_codes && elem->flags & ELEMENT_HIGHLIGHT) {
|
||||
if (ansi_invert) {
|
||||
if (value.as_long() > 0) {
|
||||
mark_red(out, elem);
|
||||
highlighted = true;
|
||||
}
|
||||
} else {
|
||||
if (value.as_long() < 0) {
|
||||
mark_red(out, elem);
|
||||
highlighted = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
out << value.as_long();
|
||||
break;
|
||||
|
||||
case value_t::DATETIME:
|
||||
out << value.as_datetime();
|
||||
break;
|
||||
|
||||
case value_t::AMOUNT:
|
||||
if (ansi_codes && elem->flags & ELEMENT_HIGHLIGHT) {
|
||||
if (ansi_invert) {
|
||||
if (value.as_amount().sign() > 0) {
|
||||
mark_red(out, elem);
|
||||
highlighted = true;
|
||||
}
|
||||
} else {
|
||||
if (value.as_amount().sign() < 0) {
|
||||
mark_red(out, elem);
|
||||
highlighted = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
out << value.as_amount();
|
||||
break;
|
||||
|
||||
case value_t::BALANCE:
|
||||
bal = &(value.as_balance());
|
||||
// fall through...
|
||||
|
||||
case value_t::BALANCE_PAIR:
|
||||
if (! bal)
|
||||
bal = &(value.as_balance_pair().quantity());
|
||||
|
||||
if (ansi_codes && elem->flags & ELEMENT_HIGHLIGHT) {
|
||||
if (ansi_invert) {
|
||||
if (*bal > 0) {
|
||||
mark_red(out, elem);
|
||||
highlighted = true;
|
||||
}
|
||||
} else {
|
||||
if (*bal < 0) {
|
||||
mark_red(out, elem);
|
||||
highlighted = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
bal->print(out, elem->min_width,
|
||||
(elem->max_width > 0 ?
|
||||
elem->max_width : elem->min_width));
|
||||
|
||||
ignore_max_width = true;
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
|
||||
if (highlighted)
|
||||
mark_plain(out);
|
||||
break;
|
||||
}
|
||||
|
||||
case element_t::OPT_AMOUNT:
|
||||
if (details.xact) {
|
||||
string disp;
|
||||
bool use_disp = false;
|
||||
|
||||
if (details.xact->cost && details.xact->amount) {
|
||||
std::ostringstream stream;
|
||||
if (! details.xact->amount_expr.expr_str.empty())
|
||||
stream << details.xact->amount_expr.expr_str;
|
||||
else
|
||||
stream << details.xact->amount.strip_annotations();
|
||||
|
||||
if (details.xact->cost_expr)
|
||||
stream << details.xact->cost_expr->expr_str;
|
||||
else
|
||||
stream << " @ " << amount_t(*details.xact->cost /
|
||||
details.xact->amount).unround();
|
||||
disp = stream.str();
|
||||
use_disp = true;
|
||||
}
|
||||
else if (details.entry) {
|
||||
unsigned int xacts_count = 0;
|
||||
xact_t * first = NULL;
|
||||
xact_t * last = NULL;
|
||||
|
||||
foreach (const transaction_t * xact, details.entry->xacts) {
|
||||
if (xact_has_xdata(*xact) &&
|
||||
xact_xdata_(*xact).dflags & XACT_TO_DISPLAY) {
|
||||
xacts_count++;
|
||||
if (! first)
|
||||
first = xact;
|
||||
last = xact;
|
||||
}
|
||||
}
|
||||
|
||||
use_disp = (xacts_count == 2 && details.xact == last &&
|
||||
first->amount == - last->amount);
|
||||
}
|
||||
|
||||
if (! use_disp) {
|
||||
if (! details.xact->amount_expr.expr_str.empty())
|
||||
out << details.xact->amount_expr.expr_str;
|
||||
else
|
||||
out << details.xact->amount.strip_annotations();
|
||||
} else {
|
||||
out << disp;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case element_t::SOURCE:
|
||||
if (details.entry && details.entry->journal) {
|
||||
int idx = details.entry->src_idx;
|
||||
foreach (const path& path, details.entry->journal->sources)
|
||||
if (! idx--) {
|
||||
out << path;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case element_t::ENTRY_BEG_POS:
|
||||
if (details.entry)
|
||||
out << (unsigned long)details.entry->beg_pos;
|
||||
break;
|
||||
|
||||
case element_t::ENTRY_BEG_LINE:
|
||||
if (details.entry)
|
||||
out << details.entry->beg_line;
|
||||
break;
|
||||
|
||||
case element_t::ENTRY_END_POS:
|
||||
if (details.entry)
|
||||
out << (unsigned long)details.entry->end_pos;
|
||||
break;
|
||||
|
||||
case element_t::ENTRY_END_LINE:
|
||||
if (details.entry)
|
||||
out << details.entry->end_line;
|
||||
break;
|
||||
|
||||
case element_t::XACT_BEG_POS:
|
||||
if (details.xact)
|
||||
out << (unsigned long)details.xact->beg_pos;
|
||||
break;
|
||||
|
||||
case element_t::XACT_BEG_LINE:
|
||||
if (details.xact)
|
||||
out << details.xact->beg_line;
|
||||
break;
|
||||
|
||||
case element_t::XACT_END_POS:
|
||||
if (details.xact)
|
||||
out << (unsigned long)details.xact->end_pos;
|
||||
break;
|
||||
|
||||
case element_t::XACT_END_LINE:
|
||||
if (details.xact)
|
||||
out << details.xact->end_line;
|
||||
break;
|
||||
|
||||
case element_t::DATE_STRING:
|
||||
out << format_date(scope.resolve("date").as_date());
|
||||
break;
|
||||
|
||||
case element_t::COMPLETE_DATE_STRING: {
|
||||
date_t actual_date;
|
||||
date_t effective_date;
|
||||
if (details.xact) {
|
||||
actual_date = details.xact->actual_date();
|
||||
effective_date = details.xact->effective_date();
|
||||
}
|
||||
else if (details.entry) {
|
||||
actual_date = details.entry->actual_date();
|
||||
effective_date = details.entry->effective_date();
|
||||
}
|
||||
|
||||
char abuf[256];
|
||||
#if 0
|
||||
// jww (2008-04-20): This needs to be rewritten
|
||||
std::strftime(abuf, 255, elem->chars.c_str(), actual_date.localtime());
|
||||
#else
|
||||
abuf[0] = '\0';
|
||||
#endif
|
||||
|
||||
if (is_valid(effective_date) && effective_date != actual_date) {
|
||||
char buf[512];
|
||||
char ebuf[256];
|
||||
#if 0
|
||||
// jww (2008-04-20): This needs to be rewritten
|
||||
std::strftime(ebuf, 255, elem->chars.c_str(),
|
||||
effective_date.localtime());
|
||||
#else
|
||||
ebuf[0] = '\0';
|
||||
#endif
|
||||
|
||||
std::strcpy(buf, abuf);
|
||||
std::strcat(buf, "=");
|
||||
std::strcat(buf, ebuf);
|
||||
|
||||
out << (elem->max_width == 0 ? buf : truncate(buf, elem->max_width));
|
||||
} else {
|
||||
out << (elem->max_width == 0 ? abuf : truncate(abuf, elem->max_width));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case element_t::CLEARED:
|
||||
if (details.xact) {
|
||||
switch (details.xact->state) {
|
||||
case xact_t::CLEARED:
|
||||
out << "* ";
|
||||
break;
|
||||
case xact_t::PENDING:
|
||||
out << "! ";
|
||||
break;
|
||||
case xact_t::UNCLEARED:
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case element_t::ENTRY_CLEARED:
|
||||
if (details.entry) {
|
||||
xact_t::state_t state;
|
||||
if (details.entry->get_state(&state))
|
||||
switch (state) {
|
||||
case xact_t::CLEARED:
|
||||
out << "* ";
|
||||
break;
|
||||
case xact_t::PENDING:
|
||||
out << "! ";
|
||||
break;
|
||||
case xact_t::UNCLEARED:
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case element_t::CODE: {
|
||||
string temp;
|
||||
if (details.entry && details.entry->code) {
|
||||
temp += "(";
|
||||
temp += *details.entry->code;
|
||||
temp += ") ";
|
||||
}
|
||||
out << temp;
|
||||
break;
|
||||
}
|
||||
|
||||
case element_t::PAYEE:
|
||||
scope.resolve("payee").dump(out, elem->min_width);
|
||||
break;
|
||||
|
||||
case element_t::OPT_NOTE:
|
||||
if (details.xact && details.xact->note)
|
||||
out << " ; ";
|
||||
// fall through...
|
||||
|
||||
case element_t::NOTE:
|
||||
if (details.xact)
|
||||
out << (elem->max_width == 0 ?
|
||||
details.xact->note : truncate(*details.xact->note,
|
||||
elem->max_width));
|
||||
break;
|
||||
|
||||
case element_t::OPT_ACCOUNT:
|
||||
if (details.entry && details.xact) {
|
||||
xact_t::state_t state;
|
||||
if (! details.entry->get_state(&state))
|
||||
switch (details.xact->state) {
|
||||
case xact_t::CLEARED:
|
||||
name = "* ";
|
||||
break;
|
||||
case xact_t::PENDING:
|
||||
name = "! ";
|
||||
break;
|
||||
case xact_t::UNCLEARED:
|
||||
break;
|
||||
}
|
||||
}
|
||||
// fall through...
|
||||
|
||||
case element_t::ACCOUNT_NAME:
|
||||
case element_t::ACCOUNT_FULLNAME:
|
||||
if (details.account) {
|
||||
name += (elem->type == element_t::ACCOUNT_FULLNAME ?
|
||||
details.account->fullname() :
|
||||
partial_account_name(*details.account));
|
||||
|
||||
if (details.xact && details.xact->has_flags(XACT_VIRTUAL)) {
|
||||
if (elem->max_width > 2)
|
||||
name = truncate(name, elem->max_width - 2, true);
|
||||
|
||||
if (details.xact->has_flags(XACT_BALANCE))
|
||||
name = string("[") + name + "]";
|
||||
else
|
||||
name = string("(") + name + ")";
|
||||
}
|
||||
else if (elem->max_width > 0)
|
||||
name = truncate(name, elem->max_width, true);
|
||||
|
||||
out << name;
|
||||
} else {
|
||||
out << " ";
|
||||
}
|
||||
break;
|
||||
|
||||
case element_t::DEPTH_SPACER:
|
||||
for (const account_t * acct = details.account;
|
||||
acct;
|
||||
acct = acct->parent)
|
||||
if (account_has_xdata(*acct) &&
|
||||
account_xdata_(*acct).dflags & ACCOUNT_DISPLAYED) {
|
||||
if (elem->min_width > 0 || elem->max_width > 0)
|
||||
out.width(elem->min_width > elem->max_width ?
|
||||
elem->min_width : elem->max_width);
|
||||
out << " ";
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
|
||||
string temp = out.str();
|
||||
|
||||
if (! ignore_max_width &&
|
||||
elem->max_width > 0 && elem->max_width < temp.length())
|
||||
truncate(temp, elem->max_width);
|
||||
out_str << temp;
|
||||
out_str << truncate(temp, elem->max_width);
|
||||
else
|
||||
out_str << temp;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
110
main.cc
110
main.cc
|
|
@ -52,6 +52,102 @@
|
|||
#endif
|
||||
|
||||
namespace ledger {
|
||||
string args_to_predicate(value_t::sequence_t::const_iterator begin,
|
||||
value_t::sequence_t::const_iterator end)
|
||||
{
|
||||
string acct_value_expr;
|
||||
string payee_value_expr;
|
||||
string note_value_expr;
|
||||
|
||||
string * value_expr;
|
||||
|
||||
enum regexp_kind_t {
|
||||
ACCOUNT_REGEXP,
|
||||
PAYEE_REGEXP,
|
||||
NOTE_REGEXP
|
||||
}
|
||||
kind = ACCOUNT_REGEXP;
|
||||
|
||||
value_expr = &acct_value_expr;
|
||||
|
||||
for ( ; begin != end; begin++) {
|
||||
const string& arg((*begin).as_string());
|
||||
|
||||
if (arg == "--") {
|
||||
kind = PAYEE_REGEXP;
|
||||
value_expr = &payee_value_expr;
|
||||
}
|
||||
else if (arg == "/") {
|
||||
kind = NOTE_REGEXP;
|
||||
value_expr = ¬e_value_expr;
|
||||
}
|
||||
else {
|
||||
if (! value_expr->empty())
|
||||
*value_expr += "|";
|
||||
|
||||
switch (kind) {
|
||||
case ACCOUNT_REGEXP:
|
||||
*value_expr += "account =~ ";
|
||||
break;
|
||||
case PAYEE_REGEXP:
|
||||
*value_expr += "payee =~ ";
|
||||
break;
|
||||
case NOTE_REGEXP:
|
||||
*value_expr += "note =~ ";
|
||||
break;
|
||||
}
|
||||
|
||||
const char * p = arg.c_str();
|
||||
if (*p == '-') {
|
||||
*value_expr += "!";
|
||||
p++;
|
||||
}
|
||||
|
||||
*value_expr += "/";
|
||||
while (*p) {
|
||||
if (*p == '/')
|
||||
*value_expr += "\\";
|
||||
*value_expr += *p;
|
||||
p++;
|
||||
}
|
||||
*value_expr += "/";
|
||||
}
|
||||
}
|
||||
|
||||
string final_value_expr;
|
||||
|
||||
if (! acct_value_expr.empty()) {
|
||||
if (! payee_value_expr.empty() ||
|
||||
! note_value_expr.empty())
|
||||
final_value_expr = string("(") + acct_value_expr + ")";
|
||||
else
|
||||
final_value_expr = acct_value_expr;
|
||||
}
|
||||
|
||||
if (! payee_value_expr.empty()) {
|
||||
if (! acct_value_expr.empty())
|
||||
final_value_expr += string("&(") + payee_value_expr + ")";
|
||||
else if (! note_value_expr.empty())
|
||||
final_value_expr = string("(") + payee_value_expr + ")";
|
||||
else
|
||||
final_value_expr = payee_value_expr;
|
||||
}
|
||||
|
||||
if (! note_value_expr.empty()) {
|
||||
if (! acct_value_expr.empty() ||
|
||||
! payee_value_expr.empty())
|
||||
final_value_expr += string("&(") + note_value_expr + ")";
|
||||
else if (acct_value_expr.empty() &&
|
||||
payee_value_expr.empty())
|
||||
final_value_expr = note_value_expr;
|
||||
}
|
||||
|
||||
DEBUG("report.predicate",
|
||||
"Regexp predicate expression = " << final_value_expr);
|
||||
|
||||
return final_value_expr;
|
||||
}
|
||||
|
||||
template <class Formatter = format_xacts>
|
||||
class xacts_report
|
||||
{
|
||||
|
|
@ -65,9 +161,19 @@ namespace ledger {
|
|||
{
|
||||
ptr_t<std::ostream> ostream(args, 0);
|
||||
var_t<string> format(args, format_name);
|
||||
report_t& report(find_scope<report_t>(args));
|
||||
|
||||
find_scope<report_t>(args).xacts_report
|
||||
(xact_handler_ptr(new Formatter(*ostream, *format)));
|
||||
if (! report.format_string.empty())
|
||||
*format = report.format_string;
|
||||
|
||||
if (! report.predicate.empty())
|
||||
report.predicate = string("(") + report.predicate + ")&";
|
||||
report.predicate +=
|
||||
args_to_predicate(++args.value().as_sequence().begin(),
|
||||
args.value().as_sequence().end());
|
||||
|
||||
report.xacts_report(xact_handler_ptr(new Formatter(*ostream,
|
||||
*format)));
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
29
mask.cc
29
mask.cc
|
|
@ -34,7 +34,7 @@
|
|||
|
||||
namespace ledger {
|
||||
|
||||
mask_t::mask_t(const string& pat) : exclude(false), expr()
|
||||
mask_t::mask_t(const string& pat) : expr()
|
||||
{
|
||||
TRACE_CTOR(mask_t, "const string&");
|
||||
*this = pat;
|
||||
|
|
@ -42,40 +42,17 @@ mask_t::mask_t(const string& pat) : exclude(false), expr()
|
|||
|
||||
mask_t& mask_t::operator=(const 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++;
|
||||
}
|
||||
|
||||
expr.assign(p);
|
||||
|
||||
expr.assign(pat.c_str(), regex::perl | regex::icase);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void mask_t::read(const char *& data)
|
||||
{
|
||||
binary::read_number(data, exclude);
|
||||
|
||||
string pattern;
|
||||
binary::read_string(data, pattern);
|
||||
|
||||
*this = pattern;
|
||||
*this = binary::read_string(data);
|
||||
}
|
||||
|
||||
void mask_t::write(std::ostream& out) const
|
||||
{
|
||||
binary::write_number(out, exclude);
|
||||
binary::write_string(out, expr.str());
|
||||
}
|
||||
|
||||
|
|
|
|||
5
mask.h
5
mask.h
|
|
@ -41,12 +41,11 @@ class mask_t
|
|||
mask_t();
|
||||
|
||||
public:
|
||||
bool exclude;
|
||||
boost::regex expr;
|
||||
|
||||
explicit mask_t(const string& pattern);
|
||||
|
||||
mask_t(const mask_t& m) : exclude(m.exclude), expr(m.expr) {
|
||||
mask_t(const mask_t& m) : expr(m.expr) {
|
||||
TRACE_CTOR(mask_t, "copy");
|
||||
}
|
||||
~mask_t() throw() {
|
||||
|
|
@ -56,7 +55,7 @@ public:
|
|||
mask_t& operator=(const string& other);
|
||||
|
||||
bool match(const string& str) const {
|
||||
return boost::regex_match(str, expr) && ! exclude;
|
||||
return boost::regex_search(str, expr);
|
||||
}
|
||||
|
||||
void read(const char *& data);
|
||||
|
|
|
|||
42
op.cc
42
op.cc
|
|
@ -428,48 +428,6 @@ void expr_t::op_t::compute(value_t& result,
|
|||
break;
|
||||
}
|
||||
|
||||
case F_CODE_MASK:
|
||||
if (details.entry && details.entry->code)
|
||||
result = as_mask().match(*details.entry->code);
|
||||
else
|
||||
result = false;
|
||||
break;
|
||||
|
||||
case F_PAYEE_MASK:
|
||||
if (details.entry)
|
||||
result = as_mask().match(details.entry->payee);
|
||||
else
|
||||
result = false;
|
||||
break;
|
||||
|
||||
case F_NOTE_MASK:
|
||||
if (details.xact && details.xact->note)
|
||||
result = as_mask().match(*details.xact->note);
|
||||
else
|
||||
result = false;
|
||||
break;
|
||||
|
||||
case F_ACCOUNT_MASK:
|
||||
if (details.account)
|
||||
result = as_mask().match(details.account->fullname());
|
||||
else
|
||||
result = false;
|
||||
break;
|
||||
|
||||
case F_SHORT_ACCOUNT_MASK:
|
||||
if (details.account)
|
||||
result = as_mask().match(details.account->name);
|
||||
else
|
||||
result = false;
|
||||
break;
|
||||
|
||||
case F_COMMODITY_MASK:
|
||||
if (details.xact)
|
||||
result = as_mask().match(details.xact->amount.commodity().base_symbol());
|
||||
else
|
||||
result = false;
|
||||
break;
|
||||
|
||||
case O_ARG: {
|
||||
long arg_index = 0;
|
||||
assert(left()->kind == INDEX);
|
||||
|
|
|
|||
123
report.cc
123
report.cc
|
|
@ -35,96 +35,6 @@
|
|||
namespace ledger {
|
||||
|
||||
#if 0
|
||||
void
|
||||
report_t::regexps_to_predicate(const std::string& command,
|
||||
std::list<std::string>::const_iterator begin,
|
||||
std::list<std::string>::const_iterator end,
|
||||
const bool account_regexp,
|
||||
const bool add_account_short_masks,
|
||||
const bool logical_and)
|
||||
{
|
||||
std::string regexps[2];
|
||||
|
||||
assert(begin != end);
|
||||
|
||||
// Treat the remaining command-line arguments as regular
|
||||
// expressions, used for refining report results.
|
||||
|
||||
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 ((*i)[0] == '+') {
|
||||
if (! regexps[0].empty())
|
||||
regexps[0] += "|";
|
||||
regexps[0] += (*i).substr(1);
|
||||
}
|
||||
else {
|
||||
if (! regexps[0].empty())
|
||||
regexps[0] += "|";
|
||||
regexps[0] += *i;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
if (regexps[i].empty())
|
||||
continue;
|
||||
|
||||
if (! predicate.empty())
|
||||
predicate += logical_and ? "&" : "|";
|
||||
|
||||
int add_predicate = 0; // 1 adds /.../, 2 adds ///.../
|
||||
if (i == 1) {
|
||||
predicate += "!";
|
||||
}
|
||||
else if (add_account_short_masks) {
|
||||
if (regexps[i].find(':') != std::string::npos ||
|
||||
regexps[i].find('.') != std::string::npos ||
|
||||
regexps[i].find('*') != std::string::npos ||
|
||||
regexps[i].find('+') != std::string::npos ||
|
||||
regexps[i].find('[') != std::string::npos ||
|
||||
regexps[i].find('(') != std::string::npos) {
|
||||
show_subtotal = true;
|
||||
add_predicate = 1;
|
||||
} else {
|
||||
add_predicate = 2;
|
||||
}
|
||||
}
|
||||
else {
|
||||
add_predicate = 1;
|
||||
}
|
||||
|
||||
if (i != 1 && command == "b" && account_regexp) {
|
||||
if (! show_related && ! show_all_related) {
|
||||
if (! display_predicate.empty())
|
||||
display_predicate += "&";
|
||||
if (! show_empty)
|
||||
display_predicate += "T&";
|
||||
|
||||
if (add_predicate == 2)
|
||||
display_predicate += "//";
|
||||
display_predicate += "/(?:";
|
||||
display_predicate += regexps[i];
|
||||
display_predicate += ")/";
|
||||
}
|
||||
else if (! show_empty) {
|
||||
if (! display_predicate.empty())
|
||||
display_predicate += "&";
|
||||
display_predicate += "T";
|
||||
}
|
||||
}
|
||||
|
||||
if (! account_regexp)
|
||||
predicate += "/";
|
||||
predicate += "/(?:";
|
||||
predicate += regexps[i];
|
||||
predicate += ")/";
|
||||
}
|
||||
}
|
||||
|
||||
void report_t::process_options(const std::string& command,
|
||||
strings_list::iterator arg,
|
||||
strings_list::iterator args_end)
|
||||
|
|
@ -342,8 +252,11 @@ report_t::chain_xact_handlers(xact_handler_ptr base_handler,
|
|||
|
||||
// This filter_xacts will only pass through xacts
|
||||
// matching the `predicate'.
|
||||
if (! predicate.empty())
|
||||
if (! predicate.empty()) {
|
||||
DEBUG("report.predicate",
|
||||
"Report predicate expression = " << predicate);
|
||||
handler.reset(new filter_xacts(handler, predicate));
|
||||
}
|
||||
|
||||
#if 0
|
||||
// budget_xacts takes a set of xacts from a data
|
||||
|
|
@ -493,31 +406,30 @@ expr_t::ptr_op_t report_t::lookup(const string& name)
|
|||
if (std::strncmp(p, "opt_", 4) == 0) {
|
||||
p = p + 4;
|
||||
switch (*p) {
|
||||
#if 0
|
||||
case 'a':
|
||||
if (std::strcmp(p, "amount") == 0)
|
||||
return MAKE_FUNCTOR(report_t::option_amount);
|
||||
break;
|
||||
#endif
|
||||
|
||||
case 'b':
|
||||
if (std::strcmp(p, "bar") == 0)
|
||||
return MAKE_FUNCTOR(report_t::option_bar);
|
||||
if (std::strcmp(p, "bar_") == 0)
|
||||
return MAKE_FUNCTOR(report_t::option_bar_);
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
if (std::strcmp(p, "format") == 0)
|
||||
return MAKE_FUNCTOR(report_t::option_format);
|
||||
else if (name.find("fmt_") == 0) {
|
||||
switch (name[4]) {
|
||||
case 't':
|
||||
return MAKE_FUNCTOR(report_t::get_amount_expr);
|
||||
#if 0
|
||||
case 'T':
|
||||
return MAKE_FUNCTOR(report_t::get_total_expr);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
if (std::strcmp(p, "F_") == 0 ||
|
||||
std::strcmp(p, "format_") == 0)
|
||||
return MAKE_FUNCTOR(report_t::option_format_);
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
if (std::strcmp(p, "l_") || std::strcmp(p, "limit_"))
|
||||
return MAKE_FUNCTOR(report_t::option_limit_);
|
||||
break;
|
||||
|
||||
#if 0
|
||||
case 't':
|
||||
if (! *(p + 1))
|
||||
return MAKE_FUNCTOR(report_t::option_amount);
|
||||
|
|
@ -529,6 +441,7 @@ expr_t::ptr_op_t report_t::lookup(const string& name)
|
|||
if (! *(p + 1))
|
||||
return MAKE_FUNCTOR(report_t::option_total);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
|
|||
25
report.h
25
report.h
|
|
@ -198,6 +198,7 @@ public:
|
|||
// Config options
|
||||
//
|
||||
|
||||
#if 0
|
||||
void eval(const string& expr) {
|
||||
expr_t(expr).calc(*this);
|
||||
}
|
||||
|
|
@ -206,34 +207,42 @@ public:
|
|||
return NULL_VALUE;
|
||||
}
|
||||
|
||||
value_t option_amount(call_scope_t& args) {
|
||||
value_t option_amount_(call_scope_t& args) {
|
||||
eval(string("t=") + args[0].as_string());
|
||||
return NULL_VALUE;
|
||||
}
|
||||
value_t option_total(call_scope_t& args) {
|
||||
value_t option_total_(call_scope_t& args) {
|
||||
eval(string("T()=") + args[0].as_string());
|
||||
return NULL_VALUE;
|
||||
}
|
||||
|
||||
value_t option_format(call_scope_t& args) {
|
||||
format_string = args[0].as_string();
|
||||
return NULL_VALUE;
|
||||
}
|
||||
|
||||
value_t option_raw(call_scope_t&) {
|
||||
raw_mode = true;
|
||||
return NULL_VALUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
value_t option_format_(call_scope_t& args) {
|
||||
format_string = args[0].as_string();
|
||||
return NULL_VALUE;
|
||||
}
|
||||
|
||||
value_t option_foo(call_scope_t&) {
|
||||
std::cout << "This is foo" << std::endl;
|
||||
return NULL_VALUE;
|
||||
}
|
||||
value_t option_bar(call_scope_t& args) {
|
||||
value_t option_bar_(call_scope_t& args) {
|
||||
std::cout << "This is bar: " << args[0] << std::endl;
|
||||
return args[0];
|
||||
}
|
||||
|
||||
value_t option_limit_(call_scope_t& args) {
|
||||
if (! predicate.empty())
|
||||
predicate += "&";
|
||||
predicate += args[0].as_string();
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
// Formatting functions
|
||||
//
|
||||
|
|
|
|||
6
xact.cc
6
xact.cc
|
|
@ -105,12 +105,12 @@ namespace {
|
|||
{
|
||||
xact_t& xact(downcast<xact_t>(*scope.parent));
|
||||
|
||||
var_t<long> width(scope, 0);
|
||||
var_t<long> max_width(scope, 0);
|
||||
|
||||
string name = xact.reported_account()->fullname();
|
||||
|
||||
if (width && *width > 2)
|
||||
name = format_t::truncate(name, *width - 2, true);
|
||||
if (max_width && *max_width > 2)
|
||||
name = format_t::truncate(name, *max_width - 2, true);
|
||||
|
||||
if (xact.has_flags(XACT_VIRTUAL)) {
|
||||
if (xact.must_balance())
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue