diff options
author | John Wiegley <johnw@newartisans.com> | 2009-02-07 05:47:21 -0400 |
---|---|---|
committer | John Wiegley <johnw@newartisans.com> | 2009-02-07 05:47:21 -0400 |
commit | ea9330adaeedbdb5a03b4f37910b30f0ddb23e29 (patch) | |
tree | 6919e137cc645b2d3be307e1d9e4129fdf971e2e /src | |
parent | 66d007db9d4f7b793d53e08acc852b2bda335e32 (diff) | |
download | fork-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.cc | 46 | ||||
-rw-r--r-- | src/global.h | 2 | ||||
-rw-r--r-- | src/option.h | 36 | ||||
-rw-r--r-- | src/report.cc | 438 | ||||
-rw-r--r-- | src/report.h | 6 | ||||
-rw-r--r-- | src/scope.h | 3 | ||||
-rw-r--r-- | src/session.cc | 47 | ||||
-rw-r--r-- | src/session.h | 2 |
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); /** |