diff options
Diffstat (limited to 'src/report.cc')
-rw-r--r-- | src/report.cc | 169 |
1 files changed, 92 insertions, 77 deletions
diff --git a/src/report.cc b/src/report.cc index 49deeb44..50a199f4 100644 --- a/src/report.cc +++ b/src/report.cc @@ -321,99 +321,114 @@ namespace { 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; + std::ostringstream expr; + bool append_and = false; - 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++) { + while (begin != end) { const string& arg((*begin).as_string()); - if (arg == "--") { - kind = PAYEE_REGEXP; - value_expr = &payee_value_expr; + bool parse_argument = true; + + if (arg == "not") { + expr << " ! "; + parse_argument = false; + append_and = false; } - else if (arg == "/") { - kind = NOTE_REGEXP; - value_expr = ¬e_value_expr; + else if (arg == "and") { + expr << " & "; + parse_argument = false; + append_and = false; + } + else if (arg == "or") { + expr << " | "; + parse_argument = false; + append_and = false; + } + else if (append_and) { + 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; - } + append_and = true; + } + if (parse_argument) { const char * p = arg.c_str(); - if (*p == '-') { - *value_expr += "!"; - p++; + + bool in_prefix = true; + bool in_suffix = false; + bool found_specifier = false; + bool saw_tag_char = false; + + for (const char * c = p; *c != '\0'; c++) { + bool consumed = false; + if (in_prefix) { + switch (*c) { + case '(': + break; + case '@': + expr << "(payee =~ /"; + found_specifier = true; + consumed = true; + break; + case '=': + expr << "(note =~ /"; + found_specifier = true; + consumed = true; + break; + case '%': + expr << "(note =~ /:"; + found_specifier = true; + saw_tag_char = true; + consumed = true; + break; + case '/': + case '_': + default: + if (! found_specifier) { + expr << "(account =~ /"; + found_specifier = true; + } + in_prefix = false; + break; + } + } else { + switch (*c) { + case ')': + if (! in_suffix) { + if (found_specifier) { + if (saw_tag_char) + expr << ':'; + expr << "/)"; + } + in_suffix = true; + } + break; + default: + if (in_suffix) + throw_(parse_error, "Invalid text in specification argument"); + break; + } + } + + if (! consumed) + expr << *c; } - *value_expr += "/"; - if (kind == NOTE_REGEXP) *value_expr += ":"; - while (*p) { - if (*p == '/') - *value_expr += "\\"; - *value_expr += *p; - p++; + if (! in_suffix) { + if (found_specifier) { + if (saw_tag_char) + expr << ':'; + expr << "/)"; + } } - if (kind == NOTE_REGEXP) *value_expr += ":"; - *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; + begin++; } - 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); + DEBUG("report.predicate", "Regexp predicate expression = " << expr.str()); - return final_value_expr; + return expr.str(); } template <class Type = xact_t, |