diff options
Diffstat (limited to 'src/report.cc')
-rw-r--r-- | src/report.cc | 336 |
1 files changed, 282 insertions, 54 deletions
diff --git a/src/report.cc b/src/report.cc index b866970f..49633350 100644 --- a/src/report.cc +++ b/src/report.cc @@ -33,6 +33,7 @@ #include "report.h" #include "session.h" +#include "pool.h" #include "format.h" #include "query.h" #include "output.h" @@ -47,6 +48,201 @@ namespace ledger { +void report_t::normalize_options(const string& verb) +{ + // Patch up some of the reporting options based on what kind of + // command it was. + +#ifdef HAVE_ISATTY + if (! HANDLED(force_color)) { + if (! HANDLED(no_color) && isatty(STDOUT_FILENO)) + HANDLER(color).on_only(string("?normalize")); + if (HANDLED(color) && ! isatty(STDOUT_FILENO)) + HANDLER(color).off(); + } + if (! HANDLED(force_pager)) { + if (HANDLED(pager_) && ! isatty(STDOUT_FILENO)) + HANDLER(pager_).off(); + } +#endif + + item_t::use_effective_date = (HANDLED(effective) && + ! HANDLED(actual_dates)); + + session.journal->commodity_pool->keep_base = HANDLED(base); + session.journal->commodity_pool->get_quotes = session.HANDLED(download); + + if (session.HANDLED(price_exp_)) + session.journal->commodity_pool->quote_leeway = + session.HANDLER(price_exp_).value.as_long(); + + if (session.HANDLED(price_db_)) + session.journal->commodity_pool->price_db = + session.HANDLER(price_db_).str(); + else + session.journal->commodity_pool->price_db = none; + + if (HANDLED(date_format_)) + set_date_format(HANDLER(date_format_).str().c_str()); + if (HANDLED(datetime_format_)) + set_datetime_format(HANDLER(datetime_format_).str().c_str()); + if (HANDLED(start_of_week_)) { + if (optional<date_time::weekdays> weekday = + string_to_day_of_week(HANDLER(start_of_week_).str())) + start_of_week = *weekday; + } + + if (verb == "print" || verb == "xact" || verb == "dump") { + HANDLER(related).on_only(string("?normalize")); + HANDLER(related_all).on_only(string("?normalize")); + } + else if (verb == "equity") { + HANDLER(equity).on_only(string("?normalize")); + } + + if (verb == "print") + HANDLER(limit_).on(string("?normalize"), "actual"); + + if (! HANDLED(empty)) + HANDLER(display_).on(string("?normalize"), "amount|(!post&total)"); + + if (verb[0] != 'b' && verb[0] != 'r') + HANDLER(base).on_only(string("?normalize")); + + // If a time period was specified with -p, check whether it also gave a + // begin and/or end to the report period (though these can be overridden + // using -b or -e). Then, if no _duration_ was specified (such as monthly), + // then ignore the period since the begin/end are the only interesting + // details. + if (HANDLED(period_)) { + if (! HANDLED(sort_all_)) + HANDLER(sort_xacts_).on_only(string("?normalize")); + + date_interval_t interval(HANDLER(period_).str()); + + if (! HANDLED(begin_) && interval.start) { + string predicate = + "date>=[" + to_iso_extended_string(*interval.start) + "]"; + HANDLER(limit_).on(string("?normalize"), predicate); + } + if (! HANDLED(end_) && interval.end) { + string predicate = + "date<[" + to_iso_extended_string(*interval.end) + "]"; + HANDLER(limit_).on(string("?normalize"), predicate); + } + + if (! interval.duration) + HANDLER(period_).off(); + } + + // If -j or -J were specified, set the appropriate format string now so as + // to avoid option ordering issues were we to have done it during the + // initial parsing of the options. + if (HANDLED(amount_data)) { + HANDLER(format_) + .on_with(string("?normalize"), HANDLER(plot_amount_format_).value); + } + else if (HANDLED(total_data)) { + HANDLER(format_) + .on_with(string("?normalize"), HANDLER(plot_total_format_).value); + } + + // If the --exchange (-X) option was used, parse out any final price + // settings that may be there. + if (HANDLED(exchange_) && + HANDLER(exchange_).str().find('=') != string::npos) { + value_t(0L).exchange_commodities(HANDLER(exchange_).str(), true, + terminus); + } + + long cols = 0; + if (HANDLED(columns_)) + cols = HANDLER(columns_).value.to_long(); + else if (const char * columns = std::getenv("COLUMNS")) + cols = lexical_cast<long>(columns); + else + cols = 80L; + + if (cols > 0) { + DEBUG("auto.columns", "cols = " << cols); + + if (! HANDLER(date_width_).specified) + HANDLER(date_width_) + .on_with(none, static_cast<long>(format_date(CURRENT_DATE(), + FMT_PRINTED).length())); + + long date_width = HANDLER(date_width_).value.to_long(); + long payee_width = (HANDLER(payee_width_).specified ? + HANDLER(payee_width_).value.to_long() : + int(double(cols) * 0.263157)); + long account_width = (HANDLER(account_width_).specified ? + HANDLER(account_width_).value.to_long() : + int(double(cols) * 0.302631)); + long amount_width = (HANDLER(amount_width_).specified ? + HANDLER(amount_width_).value.to_long() : + int(double(cols) * 0.157894)); + long total_width = (HANDLER(total_width_).specified ? + HANDLER(total_width_).value.to_long() : + amount_width); + + DEBUG("auto.columns", "date_width = " << date_width); + DEBUG("auto.columns", "payee_width = " << payee_width); + DEBUG("auto.columns", "account_width = " << account_width); + DEBUG("auto.columns", "amount_width = " << amount_width); + DEBUG("auto.columns", "total_width = " << total_width); + + if (! HANDLER(date_width_).specified && + ! HANDLER(payee_width_).specified && + ! HANDLER(account_width_).specified && + ! HANDLER(amount_width_).specified && + ! HANDLER(total_width_).specified) { + long total = (4 /* the spaces between */ + date_width + payee_width + + account_width + amount_width + total_width); + if (total > cols) { + DEBUG("auto.columns", "adjusting account down"); + account_width -= total - cols; + DEBUG("auto.columns", "account_width now = " << account_width); + } + } + + if (! HANDLER(date_width_).specified) + HANDLER(date_width_).on_with(string("?normalize"), date_width); + if (! HANDLER(payee_width_).specified) + HANDLER(payee_width_).on_with(string("?normalize"), payee_width); + if (! HANDLER(account_width_).specified) + HANDLER(account_width_).on_with(string("?normalize"), account_width); + if (! HANDLER(amount_width_).specified) + HANDLER(amount_width_).on_with(string("?normalize"), amount_width); + if (! HANDLER(total_width_).specified) + HANDLER(total_width_).on_with(string("?normalize"), total_width); + } +} + +void report_t::parse_query_args(const value_t& args, const string& whence) +{ + query_t query(args, what_to_keep()); + if (! query) + throw_(std::runtime_error, + _("Invalid query predicate: %1") << query.text()); + + HANDLER(limit_).on(whence, query.text()); + + DEBUG("report.predicate", + "Predicate = " << HANDLER(limit_).str()); + + if (query.tokens_remaining()) { + query.parse_again(); + if (! query) + throw_(std::runtime_error, + _("Invalid display predicate: %1") << query.text()); + + HANDLER(display_).on(whence, query.text()); + + DEBUG("report.predicate", + "Display predicate = " << HANDLER(display_).str()); + } +} + void report_t::posts_report(post_handler_ptr handler) { journal_posts_iterator walker(*session.journal.get()); @@ -353,6 +549,69 @@ value_t report_t::fn_lot_tag(call_scope_t& scope) return NULL_VALUE; } +value_t report_t::fn_to_boolean(call_scope_t& scope) +{ + interactive_t args(scope, "v"); + args.value_at(0).in_place_cast(value_t::BOOLEAN); + return args.value_at(0); +} + +value_t report_t::fn_to_int(call_scope_t& scope) +{ + interactive_t args(scope, "v"); + args.value_at(0).in_place_cast(value_t::INTEGER); + return args.value_at(0); +} + +value_t report_t::fn_to_datetime(call_scope_t& scope) +{ + interactive_t args(scope, "v"); + args.value_at(0).in_place_cast(value_t::DATETIME); + return args.value_at(0); +} + +value_t report_t::fn_to_date(call_scope_t& scope) +{ + interactive_t args(scope, "v"); + args.value_at(0).in_place_cast(value_t::DATE); + return args.value_at(0); +} + +value_t report_t::fn_to_amount(call_scope_t& scope) +{ + interactive_t args(scope, "v"); + args.value_at(0).in_place_cast(value_t::AMOUNT); + return args.value_at(0); +} + +value_t report_t::fn_to_balance(call_scope_t& scope) +{ + interactive_t args(scope, "v"); + args.value_at(0).in_place_cast(value_t::BALANCE); + return args.value_at(0); +} + +value_t report_t::fn_to_string(call_scope_t& scope) +{ + interactive_t args(scope, "v"); + args.value_at(0).in_place_cast(value_t::STRING); + return args.value_at(0); +} + +value_t report_t::fn_to_mask(call_scope_t& scope) +{ + interactive_t args(scope, "v"); + args.value_at(0).in_place_cast(value_t::MASK); + return args.value_at(0); +} + +value_t report_t::fn_to_sequence(call_scope_t& scope) +{ + interactive_t args(scope, "v"); + args.value_at(0).in_place_cast(value_t::SEQUENCE); + return args.value_at(0); +} + namespace { value_t fn_black(call_scope_t&) { return string_value("black"); @@ -393,54 +652,6 @@ namespace { value_t fn_null(call_scope_t&) { return NULL_VALUE; } - - template <class Type = post_t, - class handler_ptr = post_handler_ptr, - void (report_t::*report_method)(handler_ptr) = - &report_t::posts_report> - class reporter - { - shared_ptr<item_handler<Type> > handler; - - report_t& report; - string whence; - - public: - reporter(item_handler<Type> * _handler, report_t& _report, - const string& _whence) - : handler(_handler), report(_report), whence(_whence) {} - - value_t operator()(call_scope_t& args) - { - if (args.size() > 0) { - query_t query(args.value(), report.what_to_keep()); - if (! query) - throw_(std::runtime_error, - _("Invalid query predicate: %1") << query.text()); - - report.HANDLER(limit_).on(whence, query.text()); - - DEBUG("report.predicate", - "Predicate = " << report.HANDLER(limit_).str()); - - if (query.tokens_remaining()) { - query.parse_again(); - if (! query) - throw_(std::runtime_error, - _("Invalid display predicate: %1") << query.text()); - - report.HANDLER(display_).on(whence, query.text()); - - DEBUG("report.predicate", - "Display predicate = " << report.HANDLER(display_).str()); - } - } - - (report.*report_method)(handler_ptr(handler)); - - return true; - } - }; } value_t report_t::reload_command(call_scope_t&) @@ -561,6 +772,7 @@ option_t<report_t> * report_t::lookup_option(const char * p) break; case 'd': OPT(daily); + else OPT(date_); else OPT(date_format_); else OPT(datetime_format_); else OPT(depth_); @@ -634,7 +846,7 @@ option_t<report_t> * report_t::lookup_option(const char * p) else OPT(plot_total_format_); else OPT(price); else OPT(prices_format_); - else OPT(pricesdb_format_); + else OPT(pricedb_format_); else OPT(print_format_); else OPT(payee_width_); else OPT(prepend_format_); @@ -822,6 +1034,24 @@ expr_t::ptr_op_t report_t::lookup(const symbol_t::kind_t kind, return MAKE_FUNCTOR(report_t::fn_today); else if (is_eq(p, "t")) return MAKE_FUNCTOR(report_t::fn_display_amount); + else if (is_eq(p, "to_boolean")) + return MAKE_FUNCTOR(report_t::fn_to_boolean); + else if (is_eq(p, "to_int")) + return MAKE_FUNCTOR(report_t::fn_to_int); + else if (is_eq(p, "to_datetime")) + return MAKE_FUNCTOR(report_t::fn_to_datetime); + else if (is_eq(p, "to_date")) + return MAKE_FUNCTOR(report_t::fn_to_date); + else if (is_eq(p, "to_amount")) + return MAKE_FUNCTOR(report_t::fn_to_amount); + else if (is_eq(p, "to_balance")) + return MAKE_FUNCTOR(report_t::fn_to_balance); + else if (is_eq(p, "to_string")) + return MAKE_FUNCTOR(report_t::fn_to_string); + else if (is_eq(p, "to_mask")) + return MAKE_FUNCTOR(report_t::fn_to_mask); + else if (is_eq(p, "to_sequence")) + return MAKE_FUNCTOR(report_t::fn_to_sequence); break; case 'T': @@ -929,12 +1159,12 @@ expr_t::ptr_op_t report_t::lookup(const symbol_t::kind_t kind, (new format_posts(*this, report_format(HANDLER(prices_format_)), maybe_format(HANDLER(prepend_format_))), *this, "#prices")); - else if (is_eq(p, "pricesdb")) + else if (is_eq(p, "pricedb")) return expr_t::op_t::wrap_functor (reporter<post_t, post_handler_ptr, &report_t::commodities_report> - (new format_posts(*this, report_format(HANDLER(pricesdb_format_)), + (new format_posts(*this, report_format(HANDLER(pricedb_format_)), maybe_format(HANDLER(prepend_format_))), - *this, "#pricesdb")); + *this, "#pricedb")); break; case 'r': @@ -951,8 +1181,6 @@ expr_t::ptr_op_t report_t::lookup(const symbol_t::kind_t kind, case 's': if (is_eq(p, "stats") || is_eq(p, "stat")) return WRAP_FUNCTOR(report_statistics); - else if (is_eq(p, "server")) - return session.lookup(symbol_t::COMMAND, "server"); break; case 'x': |