summaryrefslogtreecommitdiff
path: root/src/report.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/report.cc')
-rw-r--r--src/report.cc336
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':