summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJohn Wiegley <johnw@newartisans.com>2009-02-07 05:47:21 -0400
committerJohn Wiegley <johnw@newartisans.com>2009-02-07 05:47:21 -0400
commitea9330adaeedbdb5a03b4f37910b30f0ddb23e29 (patch)
tree6919e137cc645b2d3be307e1d9e4129fdf971e2e /src
parent66d007db9d4f7b793d53e08acc852b2bda335e32 (diff)
downloadfork-ledger-ea9330adaeedbdb5a03b4f37910b30f0ddb23e29.tar.gz
fork-ledger-ea9330adaeedbdb5a03b4f37910b30f0ddb23e29.tar.bz2
fork-ledger-ea9330adaeedbdb5a03b4f37910b30f0ddb23e29.zip
Allow value expressions to gain access to option settings.
For example, "ledger eval options.limit" prints 0 (for false), but: "ledger -l hello eval options.limit" print "hello"s, since the value of options.limit, once set to a value, is that string. For flag options, such as -Y, eval prints 0 if unset, and 1 if set. This feature allows value expressions to be conditionalized based on the presence of user options.
Diffstat (limited to 'src')
-rw-r--r--src/global.cc46
-rw-r--r--src/global.h2
-rw-r--r--src/option.h36
-rw-r--r--src/report.cc438
-rw-r--r--src/report.h6
-rw-r--r--src/scope.h3
-rw-r--r--src/session.cc47
-rw-r--r--src/session.h2
8 files changed, 320 insertions, 260 deletions
diff --git a/src/global.cc b/src/global.cc
index 497dc397..8915d763 100644
--- a/src/global.cc
+++ b/src/global.cc
@@ -238,32 +238,40 @@ int global_scope_t::execute_command_wrapper(strings_list args, bool at_repl)
return status;
}
+option_t<global_scope_t> * global_scope_t::lookup_option(const char * p)
+{
+ switch (*p) {
+ case 'd':
+ OPT(debug_);
+ break;
+ case 'i':
+ OPT(init_file_);
+ break;
+ case 's':
+ OPT(script_);
+ break;
+ case 't':
+ OPT(trace_);
+ break;
+ case 'v':
+ OPT_(verbose);
+ else OPT(verify);
+ else OPT(version);
+ break;
+ }
+ return NULL;
+}
+
expr_t::ptr_op_t global_scope_t::lookup(const string& name)
{
const char * p = name.c_str();
switch (*p) {
case 'o':
if (WANT_OPT()) { p += OPT_PREFIX_LEN;
- switch (*p) {
- case 'd':
- OPT(debug_);
- break;
- case 'i':
- OPT(init_file_);
- break;
- case 's':
- OPT(script_);
- break;
- case 't':
- OPT(trace_);
- break;
- case 'v':
- OPT_(verbose);
- else OPT(verify);
- else OPT(version);
- break;
- }
+ if (option_t<global_scope_t> * handler = lookup_option(p))
+ return MAKE_OPT_HANDLER(global_scope_t, handler);
}
+ break;
case 'p':
if (WANT_PRECMD()) { p += PRECMD_PREFIX_LEN;
diff --git a/src/global.h b/src/global.h
index f7f10b30..85745ba2 100644
--- a/src/global.h
+++ b/src/global.h
@@ -109,6 +109,8 @@ See LICENSE file included with the distribution for details and disclaimer.";
out << std::endl;
}
+ option_t<global_scope_t> * lookup_option(const char * p);
+
virtual expr_t::ptr_op_t lookup(const string& name);
OPTION(global_scope_t, debug_);
diff --git a/src/option.h b/src/option.h
index f94ef783..00f9d8d7 100644
--- a/src/option.h
+++ b/src/option.h
@@ -130,13 +130,28 @@ public:
virtual void handler(call_scope_t& args) {
if (wants_arg)
value = args[0];
+ handled = true;
}
- virtual value_t operator()(call_scope_t& args) {
+ virtual value_t handler_wrapper(call_scope_t& args) {
handler(args);
- handled = true;
return true;
}
+
+ virtual value_t operator()(call_scope_t& args) {
+ if (! args.empty()) {
+ return handler_wrapper(args);
+ }
+ else if (wants_arg) {
+ if (handled)
+ return string_value(str());
+ else
+ return false;
+ }
+ else {
+ return handled;
+ }
+ }
};
#define BEGIN(type, name) \
@@ -156,9 +171,11 @@ public:
#define COPY_OPT(name, other) name ## _handler(other.name ## _handler)
-#define MAKE_OPT_FUNCTOR(x) \
- expr_t::op_t::wrap_functor(bind(&x ## _option_t::operator(), \
- &x ## _handler, _1))
+#define MAKE_OPT_HANDLER(type, x) \
+ expr_t::op_t::wrap_functor(bind(&option_t<type>::handler_wrapper, x, _1))
+
+#define MAKE_OPT_FUNCTOR(type, x) \
+ expr_t::op_t::wrap_functor(bind(&option_t<type>::operator(), x, _1))
inline bool is_eq(const char * p, const char * n) {
// Test whether p matches n, substituting - in p for _ in n.
@@ -166,25 +183,26 @@ inline bool is_eq(const char * p, const char * n) {
if (! (*p == '-' && *n == '_' ) && *p != *n)
return false;
}
- return *p == *n;
+ // Ignore any trailing underscore
+ return *p == *n || (! *p && *n == '_' && ! *(n + 1));
}
#define OPT(name) \
if (is_eq(p, #name)) \
- return ((name ## _handler).parent = this, MAKE_OPT_FUNCTOR(name))
+ return ((name ## _handler).parent = this, &(name ## _handler))
#define OPT_(name) \
if (! *(p + 1) || \
((name ## _handler).wants_arg && \
*(p + 1) == '_' && ! *(p + 2)) || \
is_eq(p, #name)) \
- return ((name ## _handler).parent = this, MAKE_OPT_FUNCTOR(name))
+ return ((name ## _handler).parent = this, &(name ## _handler))
#define OPT_CH(name) \
if (! *(p + 1) || \
((name ## _handler).wants_arg && \
*(p + 1) == '_' && ! *(p + 2))) \
- return ((name ## _handler).parent = this, MAKE_OPT_FUNCTOR(name))
+ return ((name ## _handler).parent = this, &(name ## _handler))
#define HANDLER(name) name ## _handler
#define HANDLED(name) HANDLER(name)
diff --git a/src/report.cc b/src/report.cc
index 5caad47c..8ab51ef1 100644
--- a/src/report.cc
+++ b/src/report.cc
@@ -288,13 +288,225 @@ namespace {
};
}
+option_t<report_t> * report_t::lookup_option(const char * p)
+{
+ switch (*p) {
+ case '%':
+ OPT_CH(percentage);
+ break;
+ case 'A':
+ OPT_CH(average);
+ break;
+ case 'B':
+ OPT_CH(basis);
+ break;
+ case 'C':
+ OPT_CH(cleared);
+ break;
+ case 'D':
+ OPT_CH(deviation);
+ break;
+ case 'E':
+ OPT_CH(empty);
+ break;
+ case 'F':
+ OPT_CH(format_);
+ break;
+ case 'G':
+ OPT_CH(gain);
+ break;
+ case 'I':
+ OPT_CH(price);
+ break;
+ case 'J':
+ OPT_CH(total_data);
+ break;
+ case 'L':
+ OPT_CH(actual);
+ break;
+ case 'M':
+ OPT_CH(monthly);
+ break;
+ case 'O':
+ OPT_CH(quantity);
+ break;
+ case 'P':
+ OPT_CH(by_payee);
+ break;
+ case 'R':
+ OPT_CH(real);
+ break;
+ case 'S':
+ OPT_CH(sort_);
+ break;
+ case 'T':
+ OPT_CH(total_);
+ break;
+ case 'U':
+ OPT_CH(uncleared);
+ break;
+ case 'V':
+ OPT_CH(market);
+ break;
+ case 'W':
+ OPT_CH(weekly);
+ break;
+ case 'Y':
+ OPT_CH(yearly);
+ break;
+ case 'Z':
+ OPT_CH(price_exp_);
+ break;
+ case 'a':
+ OPT(abbrev_len_);
+ else OPT(account_);
+ else OPT(actual);
+ else OPT(add_budget);
+ else OPT(amount_);
+ else OPT(amount_data);
+ else OPT(anon);
+ else OPT(ansi);
+ else OPT(ansi_invert);
+ else OPT(average);
+ break;
+ case 'b':
+ OPT(balance_format_);
+ else OPT(base);
+ else OPT(basis);
+ else OPT_(begin_);
+ else OPT(budget);
+ else OPT(by_payee);
+ break;
+ case 'c':
+ OPT(cache_);
+ else OPT(csv_format_);
+ else OPT(cleared);
+ else OPT(code_as_payee);
+ else OPT(collapse);
+ else OPT(comm_as_payee);
+ else OPT(cost);
+ else OPT_(current);
+ break;
+ case 'd':
+ OPT(daily);
+ else OPT(date_format_);
+ else OPT(deviation);
+ else OPT_(display_);
+ else OPT(display_amount_);
+ else OPT(display_total_);
+ else OPT(dow);
+ break;
+ case 'e':
+ OPT(effective);
+ else OPT(empty);
+ else OPT_(end_);
+ else OPT(equity_format_);
+ break;
+ case 'f':
+ OPT(forecast_);
+ else OPT(format_);
+ break;
+ case 'g':
+ OPT_CH(performance);
+ else OPT(gain);
+ break;
+ case 'h':
+ OPT(head_);
+ break;
+ case 'i':
+ OPT(invert);
+ break;
+ case 'j':
+ OPT_CH(amount_data);
+ break;
+ case 'l':
+ OPT_(limit_);
+ else OPT(lot_dates);
+ else OPT(lot_prices);
+ else OPT(lot_tags);
+ else OPT(lots);
+ break;
+ case 'm':
+ OPT(market);
+ else OPT(monthly);
+ break;
+ case 'n':
+ OPT_CH(collapse);
+ break;
+ case 'o':
+ OPT(only_);
+ else OPT_(output_);
+ break;
+ case 'p':
+ OPT(pager_);
+ else OPT(percentage);
+ else OPT(performance);
+ else OPT_(period_);
+ else OPT(period_sort_);
+ else OPT(plot_amount_format_);
+ else OPT(plot_total_format_);
+ else OPT(price);
+ else OPT(price_exp_);
+ else OPT(prices_format_);
+ else OPT(pricesdb_format_);
+ else OPT(print_format_);
+ break;
+ case 'q':
+ OPT(quantity);
+ else OPT(quarterly);
+ break;
+ case 'r':
+ OPT(real);
+ else OPT(register_format_);
+ else OPT_(related);
+ else OPT(related_all);
+ else OPT(revalued);
+ else OPT(revalued_only);
+ break;
+ case 's':
+ OPT(set_price_);
+ else OPT(sort_);
+ else OPT(sort_all_);
+ else OPT(sort_entries_);
+ else OPT_(subtotal);
+ break;
+ case 't':
+ OPT_CH(amount_);
+ else OPT(tail_);
+ else OPT(total_);
+ else OPT(total_data);
+ else OPT(totals);
+ else OPT(truncate_);
+ break;
+ case 'u':
+ OPT(unbudgeted);
+ else OPT(uncleared);
+ break;
+ case 'w':
+ OPT(weekly);
+ else OPT_(wide);
+ else OPT(wide_register_format_);
+ else OPT(write_hdr_format_);
+ else OPT(write_xact_format_);
+ break;
+ case 'x':
+ OPT_CH(comm_as_payee);
+ break;
+ case 'y':
+ OPT_CH(date_format_);
+ else OPT(yearly);
+ break;
+ }
+ return NULL;
+}
+
expr_t::ptr_op_t report_t::lookup(const string& name)
{
const char * p = name.c_str();
switch (*p) {
case 'a':
if (is_eq(p, "amount_expr"))
- MAKE_FUNCTOR(report_t::fn_amount_expr);
+ return MAKE_FUNCTOR(report_t::fn_amount_expr);
break;
case 'c':
@@ -348,12 +560,12 @@ expr_t::ptr_op_t report_t::lookup(const string& name)
break;
case 'd':
- if (is_eq(p, "display_total"))
- return MAKE_FUNCTOR(report_t::fn_display_total);
- else if (is_eq(p, "display_total"))
+ if (is_eq(p, "display_date"))
+ return MAKE_FUNCTOR(report_t::fn_display_date);
+ else if (is_eq(p, "display_amount"))
return MAKE_FUNCTOR(report_t::fn_display_amount);
else if (is_eq(p, "display_total"))
- return MAKE_FUNCTOR(report_t::fn_display_date);
+ return MAKE_FUNCTOR(report_t::fn_display_total);
break;
case 'e':
@@ -373,213 +585,11 @@ expr_t::ptr_op_t report_t::lookup(const string& name)
case 'o':
if (WANT_OPT()) { p += OPT_PREFIX_LEN;
- switch (*p) {
- case '%':
- OPT_CH(percentage);
- break;
- case 'A':
- OPT_CH(average);
- break;
- case 'B':
- OPT_CH(basis);
- break;
- case 'C':
- OPT_CH(cleared);
- break;
- case 'D':
- OPT_CH(deviation);
- break;
- case 'E':
- OPT_CH(empty);
- break;
- case 'F':
- OPT_CH(format_);
- break;
- case 'G':
- OPT_CH(gain);
- break;
- case 'I':
- OPT_CH(price);
- break;
- case 'J':
- OPT_CH(total_data);
- break;
- case 'L':
- OPT_CH(actual);
- break;
- case 'M':
- OPT_CH(monthly);
- break;
- case 'O':
- OPT_CH(quantity);
- break;
- case 'P':
- OPT_CH(by_payee);
- break;
- case 'R':
- OPT_CH(real);
- break;
- case 'S':
- OPT_CH(sort_);
- break;
- case 'T':
- OPT_CH(total_);
- break;
- case 'U':
- OPT_CH(uncleared);
- break;
- case 'V':
- OPT_CH(market);
- break;
- case 'W':
- OPT_CH(weekly);
- break;
- case 'Y':
- OPT_CH(yearly);
- break;
- case 'Z':
- OPT_CH(price_exp_);
- break;
- case 'a':
- OPT(abbrev_len_);
- else OPT(account_);
- else OPT(actual);
- else OPT(add_budget);
- else OPT(amount_);
- else OPT(amount_data);
- else OPT(anon);
- else OPT(ansi);
- else OPT(ansi_invert);
- else OPT(average);
- break;
- case 'b':
- OPT(balance_format_);
- else OPT(base);
- else OPT(basis);
- else OPT_(begin_);
- else OPT(budget);
- else OPT(by_payee);
- break;
- case 'c':
- OPT(cache_);
- else OPT(csv_format_);
- else OPT(cleared);
- else OPT(code_as_payee);
- else OPT(collapse);
- else OPT(comm_as_payee);
- else OPT(cost);
- else OPT_(current);
- break;
- case 'd':
- OPT(daily);
- else OPT(date_format_);
- else OPT(deviation);
- else OPT_(display_);
- else OPT(display_amount_);
- else OPT(display_total_);
- else OPT(dow);
- break;
- case 'e':
- OPT(effective);
- else OPT(empty);
- else OPT_(end_);
- else OPT(equity_format_);
- break;
- case 'f':
- OPT(forecast_);
- else OPT(format_);
- break;
- case 'g':
- OPT_CH(performance);
- else OPT(gain);
- break;
- case 'h':
- OPT(head_);
- break;
- case 'i':
- OPT(invert);
- break;
- case 'j':
- OPT_CH(amount_data);
- break;
- case 'l':
- OPT_(limit_);
- else OPT(lot_dates);
- else OPT(lot_prices);
- else OPT(lot_tags);
- else OPT(lots);
- break;
- case 'm':
- OPT(market);
- else OPT(monthly);
- break;
- case 'n':
- OPT_CH(collapse);
- break;
- case 'o':
- OPT(only_);
- else OPT_(output_);
- break;
- case 'p':
- OPT(pager_);
- else OPT(percentage);
- else OPT(performance);
- else OPT_(period_);
- else OPT(period_sort_);
- else OPT(plot_amount_format_);
- else OPT(plot_total_format_);
- else OPT(price);
- else OPT(price_exp_);
- else OPT(prices_format_);
- else OPT(pricesdb_format_);
- else OPT(print_format_);
- break;
- case 'q':
- OPT(quantity);
- else OPT(quarterly);
- break;
- case 'r':
- OPT(real);
- else OPT(register_format_);
- else OPT_(related);
- else OPT(related_all);
- else OPT(revalued);
- else OPT(revalued_only);
- break;
- case 's':
- OPT(set_price_);
- else OPT(sort_);
- else OPT(sort_all_);
- else OPT(sort_entries_);
- else OPT_(subtotal);
- break;
- case 't':
- OPT_CH(amount_);
- else OPT(tail_);
- else OPT(total_);
- else OPT(total_data);
- else OPT(totals);
- else OPT(truncate_);
- break;
- case 'u':
- OPT(unbudgeted);
- else OPT(uncleared);
- break;
- case 'w':
- OPT(weekly);
- else OPT_(wide);
- else OPT(wide_register_format_);
- else OPT(write_hdr_format_);
- else OPT(write_xact_format_);
- break;
- case 'x':
- OPT_CH(comm_as_payee);
- break;
- case 'y':
- OPT_CH(date_format_);
- else OPT(yearly);
- break;
- }
+ if (option_t<report_t> * handler = lookup_option(p))
+ return MAKE_OPT_HANDLER(report_t, handler);
+ }
+ else if (is_eq(p, "options")) {
+ return MAKE_FUNCTOR(report_t::fn_options);
}
break;
@@ -623,6 +633,10 @@ expr_t::ptr_op_t report_t::lookup(const string& name)
break;
}
+ // Check if they are trying to access an option's setting or value.
+ if (option_t<report_t> * handler = lookup_option(p))
+ return MAKE_OPT_FUNCTOR(report_t, handler);
+
return session.lookup(name);
}
diff --git a/src/report.h b/src/report.h
index cdfb3b4e..2c3b322d 100644
--- a/src/report.h
+++ b/src/report.h
@@ -132,6 +132,10 @@ public:
value_t fn_escape(call_scope_t& scope);
value_t fn_join(call_scope_t& scope);
+ value_t fn_options(call_scope_t& scope) {
+ return value_t(static_cast<scope_t *>(this));
+ }
+
void append_predicate(const string& str) {
if (HANDLED(limit_))
HANDLER(limit_).on(string("(") + HANDLER(limit_).str() + ")&" + str);
@@ -160,6 +164,8 @@ public:
HANDLED(base));
}
+ option_t<report_t> * report_t::lookup_option(const char * p);
+
virtual expr_t::ptr_op_t lookup(const string& name);
/**
diff --git a/src/scope.h b/src/scope.h
index 35b5332e..37ca1ccd 100644
--- a/src/scope.h
+++ b/src/scope.h
@@ -185,6 +185,9 @@ public:
std::size_t size() const {
return args.size();
}
+ bool empty() const {
+ return args.size() == 0;
+ }
};
/**
diff --git a/src/session.cc b/src/session.cc
index d84c79a3..f3d01eec 100644
--- a/src/session.cc
+++ b/src/session.cc
@@ -255,32 +255,39 @@ value_t session_t::resolve(const string& name, expr_t::scope_t& locals)
}
#endif
+option_t<session_t> * session_t::lookup_option(const char * p)
+{
+ switch (*p) {
+ case 'a':
+ OPT_(account_); // -a
+ break;
+ case 'd':
+ OPT(download); // -Q
+ break;
+ case 'f':
+ OPT_(file_); // -f
+ break;
+ case 'i':
+ OPT(input_date_format_);
+ break;
+ case 'p':
+ OPT(price_db_);
+ break;
+ case 'Q':
+ OPT_CH(download); // -Q
+ break;
+ }
+ return NULL;
+}
+
expr_t::ptr_op_t session_t::lookup(const string& name)
{
const char * p = name.c_str();
switch (*p) {
case 'o':
if (WANT_OPT()) { p += OPT_PREFIX_LEN;
- switch (*p) {
- case 'a':
- OPT_(account_); // -a
- break;
- case 'd':
- OPT(download); // -Q
- break;
- case 'f':
- OPT_(file_); // -f
- break;
- case 'i':
- OPT(input_date_format_);
- break;
- case 'p':
- OPT(price_db_);
- break;
- case 'Q':
- OPT_CH(download); // -Q
- break;
- }
+ if (option_t<session_t> * handler = lookup_option(p))
+ return MAKE_OPT_HANDLER(session_t, handler);
}
break;
}
diff --git a/src/session.h b/src/session.h
index 89530cf1..a628454a 100644
--- a/src/session.h
+++ b/src/session.h
@@ -107,6 +107,8 @@ public:
clean_accounts();
}
+ option_t<session_t> * lookup_option(const char * p);
+
virtual expr_t::ptr_op_t lookup(const string& name);
/**