diff options
-rw-r--r-- | src/main.cc | 2 | ||||
-rw-r--r-- | src/option.cc | 35 | ||||
-rw-r--r-- | src/option.h | 4 | ||||
-rw-r--r-- | src/parser.cc | 16 | ||||
-rw-r--r-- | src/report.cc | 169 | ||||
-rw-r--r-- | src/session.h | 25 |
6 files changed, 136 insertions, 115 deletions
diff --git a/src/main.cc b/src/main.cc index d6d32b7a..c50284d5 100644 --- a/src/main.cc +++ b/src/main.cc @@ -102,7 +102,7 @@ namespace ledger { TRACE_START(arguments, 1, "Processing command-line arguments"); strings_list args; - process_arguments(argc - 1, argv + 1, false, report, args); + process_arguments(argc - 1, argv + 1, report, args); if (args.empty()) { ledger::help(std::cout); diff --git a/src/option.cc b/src/option.cc index 2e74f3b0..fa7e659d 100644 --- a/src/option.cc +++ b/src/option.cc @@ -139,31 +139,36 @@ void process_environment(const char ** envp, const string& tag, } } -void process_arguments(int, char ** argv, const bool anywhere, - scope_t& scope, std::list<string>& args) +void process_arguments(int, char ** argv, scope_t& scope, + std::list<string>& args) { + bool anywhere = true; + for (char ** i = argv; *i; i++) { - if ((*i)[0] != '-') { - if (anywhere) { - args.push_back(*i); - continue; - } else { - for (; *i; i++) - args.push_back(*i); - break; - } + DEBUG("option.args", "Examining argument '" << *i << "'"); + + if (! anywhere || (*i)[0] != '-') { + DEBUG("option.args", " adding to list of real args"); + args.push_back(*i); + continue; } // --long-option or -s if ((*i)[1] == '-') { - if ((*i)[2] == '\0') - break; + if ((*i)[2] == '\0') { + DEBUG("option.args", " it's a --, ending options processing"); + anywhere = false; + continue; + } + + DEBUG("option.args", " it's an option string"); char * name = *i + 2; char * value = NULL; if (char * p = std::strchr(name, '=')) { *p++ = '\0'; value = p; + DEBUG("option.args", " read option value from option: " << value); } op_bool_tuple opt(find_option(scope, name)); @@ -172,6 +177,7 @@ void process_arguments(int, char ** argv, const bool anywhere, if (opt.get<1>() && value == NULL) { value = *++i; + DEBUG("option.args", " read option value from arg: " << value); if (value == NULL) throw_(option_error, "missing option argument for --" << name); } @@ -181,6 +187,8 @@ void process_arguments(int, char ** argv, const bool anywhere, throw_(option_error, "illegal option -"); } else { + DEBUG("option.args", " single-char option"); + typedef tuple<expr_t::ptr_op_t, bool, char> op_bool_char_tuple; std::list<op_bool_char_tuple> option_queue; @@ -199,6 +207,7 @@ void process_arguments(int, char ** argv, const bool anywhere, char * value = NULL; if (o.get<1>()) { value = *++i; + DEBUG("option.args", " read option value from arg: " << value); if (value == NULL) throw_(option_error, "missing option argument for -" << o.get<2>()); diff --git a/src/option.h b/src/option.h index df7e35b5..e758ee99 100644 --- a/src/option.h +++ b/src/option.h @@ -42,8 +42,8 @@ void process_option(const string& name, scope_t& scope, void process_environment(const char ** envp, const string& tag, scope_t& scope); -void process_arguments(int argc, char ** argv, const bool anywhere, - scope_t& scope, std::list<string>& args); +void process_arguments(int argc, char ** argv, scope_t& scope, + std::list<string>& args); DECLARE_EXCEPTION(option_error, std::runtime_error); diff --git a/src/parser.cc b/src/parser.cc index d74421f0..d54d78cd 100644 --- a/src/parser.cc +++ b/src/parser.cc @@ -215,8 +215,9 @@ expr_t::parser_t::parse_logic_expr(std::istream& in, if (node && ! (tflags & EXPR_PARSE_SINGLE)) { op_t::kind_t kind = op_t::LAST; - flags_t _flags = tflags; + flags_t _flags = tflags; token_t& tok = next_token(in, tflags); + bool negate = false; switch (tok.kind) { case token_t::EQUAL: @@ -226,11 +227,16 @@ expr_t::parser_t::parse_logic_expr(std::istream& in, kind = op_t::O_EQ; break; case token_t::NEQUAL: - kind = op_t::O_NEQ; + kind = op_t::O_EQ; + negate = true; break; case token_t::MATCH: kind = op_t::O_MATCH; break; + case token_t::NMATCH: + kind = op_t::O_MATCH; + negate = true; + break; case token_t::LESS: kind = op_t::O_LT; break; @@ -257,6 +263,12 @@ expr_t::parser_t::parse_logic_expr(std::istream& in, if (! node->right()) throw_(parse_error, tok.symbol << " operator not followed by argument"); + + if (negate) { + prev = node; + node = new op_t(op_t::O_NOT); + node->set_left(prev); + } } } 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, diff --git a/src/session.h b/src/session.h index bef9b580..a0637b2e 100644 --- a/src/session.h +++ b/src/session.h @@ -224,27 +224,12 @@ See LICENSE file included with the distribution for details and disclaimer.\n"; // Option handlers // - value_t option_file_(call_scope_t& args) { + value_t option_file_(call_scope_t& args) { // f assert(args.size() == 1); - // jww (2008-08-13): Add support for multiple files, but not between - // -f and LEDGER_FILE - if (data_file.empty()) { - data_file = args[0].as_string(); - use_cache = false; - -#if 0 - // jww (2008-08-14): Should we check whether the file exists - // before we accept it, or is this done later on? - if (! data_file.string() == "-") { - std::string path = resolve_path(optarg); - if (access(path.c_str(), R_OK) != -1) - config->data_file = path; - else - throw_(std::invalid_argument, - "The ledger file '" << path << "' does not exist or is not readable"); - } -#endif - } + + // jww (2008-08-13): Add support for multiple files + data_file = args[0].as_string(); + use_cache = false; return true; } |