summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Wiegley <johnw@newartisans.com>2009-01-22 16:27:24 -0400
committerJohn Wiegley <johnw@newartisans.com>2009-01-22 16:27:24 -0400
commit0b9f22b4d24e8fa545af2d7d448ddfe9fb3736ba (patch)
tree61bb92dac4a3adc07e6b61a4b7516252fc6abbe1
parentccedf7d57f6cc42553f1d80189bf1491df6680e2 (diff)
downloadfork-ledger-0b9f22b4d24e8fa545af2d7d448ddfe9fb3736ba.tar.gz
fork-ledger-0b9f22b4d24e8fa545af2d7d448ddfe9fb3736ba.tar.bz2
fork-ledger-0b9f22b4d24e8fa545af2d7d448ddfe9fb3736ba.zip
Redid the way command-line arguments are processed. Before, Ledger used - and
-- to mean special things after the command verb was seen. But now, what used to be specified as this: ledger -n reg cash -payable -- shell Is now specified as this: ledger reg -n cash not payable @shell It could also be specified as: ledger -n reg \(cash and not payable\) and @shell
-rw-r--r--src/main.cc2
-rw-r--r--src/option.cc35
-rw-r--r--src/option.h4
-rw-r--r--src/parser.cc16
-rw-r--r--src/report.cc169
-rw-r--r--src/session.h25
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 = &note_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;
}