Reworked the way that options are handled

This commit is contained in:
John Wiegley 2012-03-09 03:51:53 -06:00
parent ef478079e7
commit 59f5ebe2df
10 changed files with 468 additions and 539 deletions

View file

@ -1,4 +1,4 @@
.Dd March 7, 2012 .Dd March 9, 2012
.Dt ledger 1 .Dt ledger 1
.Sh NAME .Sh NAME
.Nm ledger .Nm ledger
@ -359,6 +359,7 @@ See
.It Fl \-meta-width Ar INT .It Fl \-meta-width Ar INT
.It Fl \-monthly Pq Fl M .It Fl \-monthly Pq Fl M
.It Fl \-no-color .It Fl \-no-color
.It Fl \-no-pager
.It Fl \-no-rounding .It Fl \-no-rounding
.It Fl \-no-titles .It Fl \-no-titles
.It Fl \-no-total .It Fl \-no-total

View file

@ -88,10 +88,9 @@ post_handler_ptr chain_pre_post_handlers(post_handler_ptr base_handler,
predicate_t(report.HANDLER(forecast_while_).str(), predicate_t(report.HANDLER(forecast_while_).str(),
report.what_to_keep()), report.what_to_keep()),
report, report,
report.HANDLED(forecast_years_) ? (report.HANDLED(forecast_years_) ?
static_cast<std::size_t> lexical_cast<std::size_t>
(report.HANDLER(forecast_years_).value.to_long()) : (report.HANDLER(forecast_years_).value) : 5UL));
5UL);
forecast_handler->add_period_xacts(report.session.journal->period_xacts); forecast_handler->add_period_xacts(report.session.journal->period_xacts);
handler.reset(forecast_handler); handler.reset(forecast_handler);
@ -137,9 +136,9 @@ post_handler_ptr chain_post_handlers(post_handler_ptr base_handler,
handler.reset handler.reset
(new truncate_xacts(handler, (new truncate_xacts(handler,
report.HANDLED(head_) ? report.HANDLED(head_) ?
report.HANDLER(head_).value.to_int() : 0, lexical_cast<int>(report.HANDLER(head_).value) : 0,
report.HANDLED(tail_) ? report.HANDLED(tail_) ?
report.HANDLER(tail_).value.to_int() : 0)); lexical_cast<int>(report.HANDLER(tail_).value) : 0));
// display_filter_posts adds virtual posts to the list to account // display_filter_posts adds virtual posts to the list to account
// for changes in value of commodities, which otherwise would affect // for changes in value of commodities, which otherwise would affect

View file

@ -522,7 +522,7 @@ value_t xact_command(call_scope_t& args)
xact_t * new_xact = draft.insert(*report.session.journal.get()); xact_t * new_xact = draft.insert(*report.session.journal.get());
// Only consider actual postings for the "xact" command // Only consider actual postings for the "xact" command
report.HANDLER(limit_).on(string("#xact"), "actual"); report.HANDLER(limit_).on("#xact", "actual");
if (new_xact) if (new_xact)
report.xact_report(post_handler_ptr(new print_xacts(report)), *new_xact); report.xact_report(post_handler_ptr(new print_xacts(report)), *new_xact);

View file

@ -61,9 +61,9 @@ protected:
option_t& operator=(const option_t&); option_t& operator=(const option_t&);
public: public:
T * parent; T * parent;
value_t value; string value;
bool wants_arg; bool wants_arg;
option_t(const char * _name, const char _ch = '\0') option_t(const char * _name, const char _ch = '\0')
: name(_name), name_len(std::strlen(name)), ch(_ch), : name(_name), name_len(std::strlen(name)), ch(_ch),
@ -94,7 +94,8 @@ public:
out << std::right << desc(); out << std::right << desc();
if (wants_arg) { if (wants_arg) {
out << " = "; out << " = ";
value.print(out, 42); out.width(42);
out << value;
} else { } else {
out.width(45); out.width(45);
out << ' '; out << ' ';
@ -123,43 +124,49 @@ public:
return handled; return handled;
} }
string& str() {
assert(handled);
if (! value)
throw_(std::runtime_error, _("No argument provided for %1") << desc());
return value.as_string_lval();
}
string str() const { string str() const {
assert(handled); assert(handled);
if (! value) if (value.empty())
throw_(std::runtime_error, _("No argument provided for %1") << desc()); throw_(std::runtime_error, _("No argument provided for %1") << desc());
return value.as_string(); return value;
} }
void on_only(const optional<string>& whence) { void on(const char * whence) {
on(string(whence));
}
void on(const optional<string>& whence) {
handler_thunk(whence);
handled = true; handled = true;
source = whence; source = whence;
} }
void on(const optional<string>& whence, const string& str) {
on_with(whence, string_value(str)); void on(const char * whence, const string& str) {
on(string(whence), str);
} }
virtual void on_with(const optional<string>& whence, void on(const optional<string>& whence, const string& str) {
const value_t& val) { string before = value;
handler_thunk(whence, str);
if (value == before)
value = str;
handled = true; handled = true;
value = val;
source = whence; source = whence;
} }
void off() { void off() {
handled = false; handled = false;
value = value_t(); value = "";
source = none; source = none;
} }
virtual void handler_thunk(call_scope_t&) {} virtual void handler_thunk(const optional<string>& whence) {}
virtual void handler_thunk(const optional<string>& whence,
const string& str) {}
virtual void handler(call_scope_t& args) { value_t handler(call_scope_t& args) {
if (wants_arg) { if (wants_arg) {
if (args.size() < 2) if (args.size() < 2)
throw_(std::runtime_error, _("No argument provided for %1") << desc()); throw_(std::runtime_error, _("No argument provided for %1") << desc());
@ -167,7 +174,7 @@ public:
throw_(std::runtime_error, _("To many arguments provided for %1") << desc()); throw_(std::runtime_error, _("To many arguments provided for %1") << desc());
else if (! args[0].is_string()) else if (! args[0].is_string())
throw_(std::runtime_error, _("Context argument for %1 not a string") << desc()); throw_(std::runtime_error, _("Context argument for %1 not a string") << desc());
on_with(args.get<string>(0), args[1]); on(args.get<string>(0), args.get<string>(1));
} }
else if (args.size() < 1) { else if (args.size() < 1) {
throw_(std::runtime_error, _("No argument provided for %1") << desc()); throw_(std::runtime_error, _("No argument provided for %1") << desc());
@ -176,27 +183,18 @@ public:
throw_(std::runtime_error, _("Context argument for %1 not a string") << desc()); throw_(std::runtime_error, _("Context argument for %1 not a string") << desc());
} }
else { else {
on_only(args.get<string>(0)); on(args.get<string>(0));
} }
handler_thunk(args);
}
virtual value_t handler_wrapper(call_scope_t& args) {
handler(args);
return true; return true;
} }
virtual value_t operator()(call_scope_t& args) { virtual value_t operator()(call_scope_t& args) {
if (! args.empty()) { if (! args.empty()) {
args.push_front(string_value("?expr")); args.push_front(string_value("?expr"));
return handler_wrapper(args); return handler(args);
} }
else if (wants_arg) { else if (wants_arg) {
if (handled) return string_value(value);
return value;
else
return NULL_VALUE;
} }
else { else {
return handled; return handled;
@ -215,15 +213,16 @@ public:
vartype var ; \ vartype var ; \
name ## option_t() : option_t<type>(#name), var value name ## option_t() : option_t<type>(#name), var value
#define DO() virtual void handler_thunk(call_scope_t&) #define DO() virtual void handler_thunk(const optional<string>& whence)
#define DO_(var) virtual void handler_thunk(call_scope_t& var) #define DO_(var) virtual void handler_thunk(const optional<string>& whence, \
const string& var)
#define END(name) name ## handler #define END(name) name ## handler
#define COPY_OPT(name, other) name ## handler(other.name ## handler) #define COPY_OPT(name, other) name ## handler(other.name ## handler)
#define MAKE_OPT_HANDLER(type, x) \ #define MAKE_OPT_HANDLER(type, x) \
expr_t::op_t::wrap_functor(bind(&option_t<type>::handler_wrapper, x, _1)) expr_t::op_t::wrap_functor(bind(&option_t<type>::handler, x, _1))
#define MAKE_OPT_FUNCTOR(type, x) \ #define MAKE_OPT_FUNCTOR(type, x) \
expr_t::op_t::wrap_functor(bind(&option_t<type>::operator(), x, _1)) expr_t::op_t::wrap_functor(bind(&option_t<type>::operator(), x, _1))
@ -284,6 +283,10 @@ inline bool is_eq(const char * p, const char * n) {
} \ } \
END(name) END(name)
#define OTHER(name) \
parent->HANDLER(name).parent = parent; \
parent->HANDLER(name)
bool process_option(const string& whence, const string& name, scope_t& scope, bool process_option(const string& whence, const string& name, scope_t& scope,
const char * arg, const string& varname); const char * arg, const string& varname);

View file

@ -133,7 +133,7 @@ namespace {
std::size_t columns = std::size_t columns =
(report.HANDLED(columns_) ? (report.HANDLED(columns_) ?
static_cast<std::size_t>(report.HANDLER(columns_).value.to_long()) : 80); lexical_cast<std::size_t>(report.HANDLER(columns_).str()) : 80);
if (xact.note) if (xact.note)
print_note(out, *xact.note, xact.has_flags(ITEM_NOTE_ON_NEXT_LINE), print_note(out, *xact.note, xact.has_flags(ITEM_NOTE_ON_NEXT_LINE),
@ -191,8 +191,8 @@ namespace {
unistring name(pbuf.str()); unistring name(pbuf.str());
std::size_t account_width = std::size_t account_width =
(report.HANDLER(account_width_).specified ? (report.HANDLED(account_width_) ?
static_cast<std::size_t>(report.HANDLER(account_width_).value.to_long()) : 36); lexical_cast<std::size_t>(report.HANDLER(account_width_).str()) : 36);
if (account_width < name.length()) if (account_width < name.length())
account_width = name.length(); account_width = name.length();
@ -218,13 +218,14 @@ namespace {
// first. // first.
} }
else { else {
int amount_width = std::size_t amount_width =
(report.HANDLER(amount_width_).specified ? (report.HANDLED(amount_width_) ?
report.HANDLER(amount_width_).value.to_int() : 12); lexical_cast<std::size_t>(report.HANDLER(amount_width_).str()) :
12);
std::ostringstream amt_str; std::ostringstream amt_str;
value_t(post->amount).print(amt_str, amount_width, -1, value_t(post->amount).print(amt_str, static_cast<int>(amount_width),
AMOUNT_PRINT_RIGHT_JUSTIFY | -1, AMOUNT_PRINT_RIGHT_JUSTIFY |
AMOUNT_PRINT_NO_COMPUTED_ANNOTATIONS); AMOUNT_PRINT_NO_COMPUTED_ANNOTATIONS);
amt = amt_str.str(); amt = amt_str.str();
} }

View file

@ -136,8 +136,8 @@ public:
virtual expr_t::ptr_op_t lookup(const symbol_t::kind_t kind, virtual expr_t::ptr_op_t lookup(const symbol_t::kind_t kind,
const string& name); const string& name);
OPTION_(python_interpreter_t, import_, DO_(args) { OPTION_(python_interpreter_t, import_, DO_(str) {
parent->import_option(args.get<string>(1)); parent->import_option(str);
}); });
}; };

View file

@ -59,7 +59,7 @@ void report_t::normalize_options(const string& verb)
#ifdef HAVE_ISATTY #ifdef HAVE_ISATTY
if (! HANDLED(force_color)) { if (! HANDLED(force_color)) {
if (! HANDLED(no_color) && isatty(STDOUT_FILENO)) if (! HANDLED(no_color) && isatty(STDOUT_FILENO))
HANDLER(color).on_only(string("?normalize")); HANDLER(color).on("?normalize");
if (HANDLED(color) && ! isatty(STDOUT_FILENO)) if (HANDLED(color) && ! isatty(STDOUT_FILENO))
HANDLER(color).off(); HANDLER(color).off();
} }
@ -83,7 +83,7 @@ void report_t::normalize_options(const string& verb)
if (session.HANDLED(price_exp_)) if (session.HANDLED(price_exp_))
commodity_pool_t::current_pool->quote_leeway = commodity_pool_t::current_pool->quote_leeway =
session.HANDLER(price_exp_).value.as_long(); lexical_cast<long>(session.HANDLER(price_exp_).value) * 3600L;
if (session.HANDLED(price_db_)) if (session.HANDLED(price_db_))
commodity_pool_t::current_pool->price_db = session.HANDLER(price_db_).str(); commodity_pool_t::current_pool->price_db = session.HANDLER(price_db_).str();
@ -106,39 +106,35 @@ void report_t::normalize_options(const string& verb)
if (! HANDLED(meta_width_)) { if (! HANDLED(meta_width_)) {
string::size_type i = HANDLER(meta_).str().find(':'); string::size_type i = HANDLER(meta_).str().find(':');
if (i != string::npos) { if (i != string::npos) {
HANDLED(meta_width_).on_with HANDLED(meta_width_).on("?normalize",
(string("?normalize"), string(HANDLER(meta_).str(), i + 1));
lexical_cast<long>(string(HANDLER(meta_).str(), i + 1))); HANDLED(meta_).on("?normalize",
HANDLED(meta_).on(string("?normalize"),
string(HANDLER(meta_).str(), 0, i)); string(HANDLER(meta_).str(), 0, i));
} }
} }
if (HANDLED(meta_width_)) { if (HANDLED(meta_width_)) {
HANDLER(prepend_format_).on HANDLER(prepend_format_)
(string("?normalize"), .on("?normalize", string("%(justify(truncated(tag(\"") +
string("%(justify(truncated(tag(\"") + HANDLER(meta_).str() + "\"), " +
HANDLER(meta_).str() + "\"), " + HANDLED(meta_width_).value + " - 1), " +
HANDLED(meta_width_).value.to_string() + " - 1), " + HANDLED(meta_width_).value + "))");
HANDLED(meta_width_).value.to_string() + "))"); meta_width = lexical_cast<long>(HANDLED(meta_width_).value);
meta_width = HANDLED(meta_width_).value.to_long();
} else { } else {
HANDLER(prepend_format_).on(string("?normalize"), string("%(tag(\"") + HANDLER(prepend_format_)
HANDLER(meta_).str() + "\"))"); .on("?normalize", string("%(tag(\"") + HANDLER(meta_).str() + "\"))");
} }
} }
if (! HANDLED(prepend_width_))
HANDLER(prepend_width_).on_with(string("?normalize"), static_cast<long>(0));
if (verb == "print" || verb == "xact" || verb == "dump") { if (verb == "print" || verb == "xact" || verb == "dump") {
HANDLER(related).on_only(string("?normalize")); HANDLER(related_all).parent = this;
HANDLER(related_all).on_only(string("?normalize")); HANDLER(related_all).on("?normalize");
} }
else if (verb == "equity") { else if (verb == "equity") {
HANDLER(equity).on_only(string("?normalize")); HANDLER(equity).on("?normalize");
} }
if (verb[0] != 'b' && verb[0] != 'r') if (verb[0] != 'b' && verb[0] != 'r')
HANDLER(base).on_only(string("?normalize")); HANDLER(base).on("?normalize");
// If a time period was specified with -p, check whether it also gave a // 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 // begin and/or end to the report period (though these can be overridden
@ -152,12 +148,10 @@ void report_t::normalize_options(const string& verb)
// to avoid option ordering issues were we to have done it during the // to avoid option ordering issues were we to have done it during the
// initial parsing of the options. // initial parsing of the options.
if (HANDLED(amount_data)) { if (HANDLED(amount_data)) {
HANDLER(format_) HANDLER(format_).on("?normalize", HANDLER(plot_amount_format_).value);
.on_with(string("?normalize"), HANDLER(plot_amount_format_).value);
} }
else if (HANDLED(total_data)) { else if (HANDLED(total_data)) {
HANDLER(format_) HANDLER(format_).on("?normalize", HANDLER(plot_total_format_).value);
.on_with(string("?normalize"), HANDLER(plot_total_format_).value);
} }
// If the --exchange (-X) option was used, parse out any final price // If the --exchange (-X) option was used, parse out any final price
@ -170,7 +164,7 @@ void report_t::normalize_options(const string& verb)
long cols = 0; long cols = 0;
if (HANDLED(columns_)) if (HANDLED(columns_))
cols = HANDLER(columns_).value.to_long(); cols = lexical_cast<long>(HANDLER(columns_).value);
else if (const char * columns = std::getenv("COLUMNS")) else if (const char * columns = std::getenv("COLUMNS"))
cols = lexical_cast<long>(columns); cols = lexical_cast<long>(columns);
else else
@ -182,23 +176,20 @@ void report_t::normalize_options(const string& verb)
if (cols > 0) { if (cols > 0) {
DEBUG("auto.columns", "cols = " << cols); DEBUG("auto.columns", "cols = " << cols);
if (! HANDLER(date_width_).specified) long date_width = (HANDLED(date_width_) ?
HANDLER(date_width_) lexical_cast<long>(HANDLER(date_width_).str()) :
.on_with(none, static_cast<long>(format_date(CURRENT_DATE(), format_date(CURRENT_DATE(),FMT_PRINTED).length());
FMT_PRINTED).length())); long payee_width = (HANDLED(payee_width_) ?
lexical_cast<long>(HANDLER(payee_width_).str()) :
long date_width = HANDLER(date_width_).value.to_long(); long(double(cols) * 0.263157));
long payee_width = (HANDLER(payee_width_).specified ? long account_width = (HANDLED(account_width_) ?
HANDLER(payee_width_).value.to_long() : lexical_cast<long>(HANDLER(account_width_).str()) :
int(double(cols) * 0.263157)); long(double(cols) * 0.302631));
long account_width = (HANDLER(account_width_).specified ? long amount_width = (HANDLED(amount_width_) ?
HANDLER(account_width_).value.to_long() : lexical_cast<long>(HANDLER(amount_width_).str()) :
int(double(cols) * 0.302631)); long(double(cols) * 0.157894));
long amount_width = (HANDLER(amount_width_).specified ? long total_width = (HANDLED(total_width_) ?
HANDLER(amount_width_).value.to_long() : lexical_cast<long>(HANDLER(total_width_).str()) :
int(double(cols) * 0.157894));
long total_width = (HANDLER(total_width_).specified ?
HANDLER(total_width_).value.to_long() :
amount_width); amount_width);
DEBUG("auto.columns", "date_width = " << date_width); DEBUG("auto.columns", "date_width = " << date_width);
@ -207,11 +198,11 @@ void report_t::normalize_options(const string& verb)
DEBUG("auto.columns", "amount_width = " << amount_width); DEBUG("auto.columns", "amount_width = " << amount_width);
DEBUG("auto.columns", "total_width = " << total_width); DEBUG("auto.columns", "total_width = " << total_width);
if (! HANDLER(date_width_).specified && if (! HANDLED(date_width_) &&
! HANDLER(payee_width_).specified && ! HANDLED(payee_width_) &&
! HANDLER(account_width_).specified && ! HANDLED(account_width_) &&
! HANDLER(amount_width_).specified && ! HANDLED(amount_width_) &&
! HANDLER(total_width_).specified) { ! HANDLED(total_width_)) {
long total = (4 /* the spaces between */ + date_width + payee_width + long total = (4 /* the spaces between */ + date_width + payee_width +
account_width + amount_width + total_width); account_width + amount_width + total_width);
if (total > cols) { if (total > cols) {
@ -222,17 +213,19 @@ void report_t::normalize_options(const string& verb)
} }
if (! HANDLED(meta_width_)) if (! HANDLED(meta_width_))
HANDLER(meta_width_).on_with(string("?normalize"), 0L); HANDLER(meta_width_).value = "0";
if (! HANDLER(date_width_).specified) if (! HANDLED(prepend_width_))
HANDLER(date_width_).on_with(string("?normalize"), date_width); HANDLER(prepend_width_).value = "0";
if (! HANDLER(payee_width_).specified) if (! HANDLED(date_width_))
HANDLER(payee_width_).on_with(string("?normalize"), payee_width); HANDLER(date_width_).value = to_string(date_width);
if (! HANDLER(account_width_).specified) if (! HANDLED(payee_width_))
HANDLER(account_width_).on_with(string("?normalize"), account_width); HANDLER(payee_width_).value = to_string(payee_width);
if (! HANDLER(amount_width_).specified) if (! HANDLED(account_width_))
HANDLER(amount_width_).on_with(string("?normalize"), amount_width); HANDLER(account_width_).value = to_string(account_width);
if (! HANDLER(total_width_).specified) if (! HANDLED(amount_width_))
HANDLER(total_width_).on_with(string("?normalize"), total_width); HANDLER(amount_width_).value = to_string(amount_width);
if (! HANDLED(total_width_))
HANDLER(total_width_).value = to_string(total_width);
} }
} }
@ -255,7 +248,7 @@ void report_t::normalize_period()
if (! interval.duration) if (! interval.duration)
HANDLER(period_).off(); HANDLER(period_).off();
else if (! HANDLED(sort_all_)) else if (! HANDLED(sort_all_))
HANDLER(sort_xacts_).on_only(string("?normalize")); HANDLER(sort_xacts_).on("?normalize");
} }
void report_t::parse_query_args(const value_t& args, const string& whence) void report_t::parse_query_args(const value_t& args, const string& whence)
@ -278,7 +271,7 @@ void report_t::parse_query_args(const value_t& args, const string& whence)
} }
if (query.has_query(query_t::QUERY_BOLD)) { if (query.has_query(query_t::QUERY_BOLD)) {
HANDLER(bold_if_).set_expr(whence, query.get_query(query_t::QUERY_BOLD)); HANDLER(bold_if_).on(whence, query.get_query(query_t::QUERY_BOLD));
DEBUG("report.predicate", "Bolding predicate = " << HANDLER(bold_if_).str()); DEBUG("report.predicate", "Bolding predicate = " << HANDLER(bold_if_).str());
} }
@ -329,9 +322,9 @@ void report_t::generate_report(post_handler_ptr handler)
generate_posts_iterator walker generate_posts_iterator walker
(session, HANDLED(seed_) ? (session, HANDLED(seed_) ?
static_cast<unsigned int>(HANDLER(seed_).value.to_long()) : 0, lexical_cast<unsigned int>(HANDLER(seed_).str()) : 0,
HANDLED(head_) ? HANDLED(head_) ?
static_cast<unsigned int>(HANDLER(head_).value.to_long()) : 50); lexical_cast<unsigned int>(HANDLER(head_).str()) : 50);
pass_down_posts<generate_posts_iterator>(handler, walker); pass_down_posts<generate_posts_iterator>(handler, walker);
} }
@ -527,16 +520,17 @@ value_t report_t::fn_market(call_scope_t& args)
arg0 = tmp; arg0 = tmp;
} }
string target_commodity;
if (args.has<string>(2)) if (args.has<string>(2))
result = arg0.exchange_commodities(args.get<string>(2), target_commodity = args.get<string>(2);
if (! target_commodity.empty())
result = arg0.exchange_commodities(target_commodity,
/* add_prices= */ false, moment); /* add_prices= */ false, moment);
else else
result = arg0.value(moment); result = arg0.value(moment);
if (! result.is_null()) return ! result.is_null() ? result : arg0;
return result;
return args[0];
} }
value_t report_t::fn_get_at(call_scope_t& args) value_t report_t::fn_get_at(call_scope_t& args)
@ -1245,7 +1239,7 @@ expr_t::ptr_op_t report_t::lookup(const symbol_t::kind_t kind,
else if (is_eq(p, "display_total")) else if (is_eq(p, "display_total"))
return MAKE_FUNCTOR(report_t::fn_display_total); return MAKE_FUNCTOR(report_t::fn_display_total);
else if (is_eq(p, "date")) else if (is_eq(p, "date"))
return MAKE_FUNCTOR(report_t::fn_now); return MAKE_FUNCTOR(report_t::fn_today);
break; break;
case 'f': case 'f':
@ -1404,85 +1398,98 @@ expr_t::ptr_op_t report_t::lookup(const symbol_t::kind_t kind,
return MAKE_OPT_HANDLER(report_t, handler); return MAKE_OPT_HANDLER(report_t, handler);
break; break;
#define POSTS_REPORT(formatter) \ #define POSTS_REPORTER(formatter) \
WRAP_FUNCTOR(reporter<>(post_handler_ptr(formatter), *this, \ WRAP_FUNCTOR(reporter<>(post_handler_ptr(formatter), *this, \
string("#") + p)); string("#") + p))
// Can't use WRAP_FUNCTOR here because the template arguments // Can't use WRAP_FUNCTOR here because the template arguments
// confuse the parser // confuse the parser
#define POSTS_REPORT_(method, formatter) \ #define POSTS_REPORTER_(method, formatter) \
expr_t::op_t::wrap_functor \ expr_t::op_t::wrap_functor \
(reporter<post_t, post_handler_ptr, method> \ (reporter<post_t, post_handler_ptr, method> \
(post_handler_ptr(formatter), *this, string("#") + p)); (post_handler_ptr(formatter), *this, string("#") + p))
#define ACCOUNTS_REPORT(formatter) \ #define FORMATTED_POSTS_REPORTER(format) \
POSTS_REPORTER \
(new format_posts \
(*this, report_format(HANDLER(format)), \
maybe_format(HANDLER(prepend_format_)), \
HANDLED(prepend_width_) ? \
lexical_cast<std::size_t>(HANDLER(prepend_width_).str()) : 0))
#define FORMATTED_COMMODITIES_REPORTER(format) \
POSTS_REPORTER_ \
(&report_t::commodities_report, \
new format_posts \
(*this, report_format(HANDLER(format)), \
maybe_format(HANDLER(prepend_format_)), \
HANDLED(prepend_width_) ? \
lexical_cast<std::size_t>(HANDLER(prepend_width_).str()) : 0))
#define ACCOUNTS_REPORTER(formatter) \
expr_t::op_t::wrap_functor(reporter<account_t, acct_handler_ptr, \ expr_t::op_t::wrap_functor(reporter<account_t, acct_handler_ptr, \
&report_t::accounts_report> \ &report_t::accounts_report> \
(acct_handler_ptr(formatter), *this, \ (acct_handler_ptr(formatter), *this, \
string("#") + p)); string("#") + p))
#define FORMATTED_ACCOUNTS_REPORTER(format) \
ACCOUNTS_REPORTER \
(new format_accounts \
(*this, report_format(HANDLER(format)), \
maybe_format(HANDLER(prepend_format_)), \
HANDLED(prepend_width_) ? \
lexical_cast<std::size_t>(HANDLER(prepend_width_).str()) : 0))
case symbol_t::COMMAND: case symbol_t::COMMAND:
switch (*p) { switch (*p) {
case 'a': case 'a':
if (is_eq(p, "accounts")) { if (is_eq(p, "accounts")) {
return POSTS_REPORT(new report_accounts(*this)); return POSTS_REPORTER(new report_accounts(*this));
} }
break; break;
case 'b': case 'b':
if (*(p + 1) == '\0' || is_eq(p, "bal") || is_eq(p, "balance")) { if (*(p + 1) == '\0' || is_eq(p, "bal") || is_eq(p, "balance")) {
return ACCOUNTS_REPORT(new format_accounts return FORMATTED_ACCOUNTS_REPORTER(balance_format_);
(*this, report_format(HANDLER(balance_format_)),
maybe_format(HANDLER(prepend_format_)),
HANDLER(prepend_width_).value.to_size_t()));
} }
else if (is_eq(p, "budget")) { else if (is_eq(p, "budget")) {
HANDLER(amount_).set_expr(string("#budget"), "(amount, 0)"); HANDLER(amount_).on(string("#budget"), "(amount, 0)");
budget_flags |= BUDGET_WRAP_VALUES; budget_flags |= BUDGET_WRAP_VALUES;
if (! (budget_flags & ~BUDGET_WRAP_VALUES)) if (! (budget_flags & ~BUDGET_WRAP_VALUES))
budget_flags |= BUDGET_BUDGETED; budget_flags |= BUDGET_BUDGETED;
return ACCOUNTS_REPORT(new format_accounts return FORMATTED_ACCOUNTS_REPORTER(budget_format_);
(*this, report_format(HANDLER(budget_format_)),
maybe_format(HANDLER(prepend_format_)),
HANDLER(prepend_width_).value.to_size_t()));
} }
break; break;
case 'c': case 'c':
if (is_eq(p, "csv")) { if (is_eq(p, "csv")) {
return POSTS_REPORT(new format_posts return FORMATTED_POSTS_REPORTER(csv_format_);
(*this, report_format(HANDLER(csv_format_)),
maybe_format(HANDLER(prepend_format_)),
HANDLER(prepend_width_).value.to_size_t()));
} }
else if (is_eq(p, "cleared")) { else if (is_eq(p, "cleared")) {
HANDLER(amount_).set_expr(string("#cleared"), HANDLER(amount_).on(string("#cleared"),
"(amount, cleared ? amount : 0)"); "(amount, cleared ? amount : 0)");
return ACCOUNTS_REPORT(new format_accounts return FORMATTED_ACCOUNTS_REPORTER(cleared_format_);
(*this, report_format(HANDLER(cleared_format_)),
maybe_format(HANDLER(prepend_format_)),
HANDLER(prepend_width_).value.to_size_t()));
} }
else if (is_eq(p, "convert")) { else if (is_eq(p, "convert")) {
return WRAP_FUNCTOR(convert_command); return WRAP_FUNCTOR(convert_command);
} }
else if (is_eq(p, "commodities")) { else if (is_eq(p, "commodities")) {
return POSTS_REPORT(new report_commodities(*this)); return POSTS_REPORTER(new report_commodities(*this));
} }
break; break;
case 'e': case 'e':
if (is_eq(p, "equity")) { if (is_eq(p, "equity")) {
HANDLER(generated).on_only(string("#equity")); HANDLER(generated).on("#equity");
return POSTS_REPORT(new print_xacts(*this)); return POSTS_REPORTER(new print_xacts(*this));
} }
else if (is_eq(p, "entry")) { else if (is_eq(p, "entry")) {
return WRAP_FUNCTOR(xact_command); return WRAP_FUNCTOR(xact_command);
} }
else if (is_eq(p, "emacs")) { else if (is_eq(p, "emacs")) {
return POSTS_REPORT(new format_emacs_posts(output_stream)); return POSTS_REPORTER(new format_emacs_posts(output_stream));
} }
else if (is_eq(p, "echo")) { else if (is_eq(p, "echo")) {
return MAKE_FUNCTOR(report_t::echo_command); return MAKE_FUNCTOR(report_t::echo_command);
@ -1491,43 +1498,32 @@ expr_t::ptr_op_t report_t::lookup(const symbol_t::kind_t kind,
case 'o': case 'o':
if (is_eq(p, "org")) { if (is_eq(p, "org")) {
return POSTS_REPORT(new posts_to_org_table return POSTS_REPORTER(new posts_to_org_table
(*this, maybe_format(HANDLER(prepend_format_)))); (*this, maybe_format(HANDLER(prepend_format_))));
} }
break; break;
case 'p': case 'p':
if (*(p + 1) == '\0' || is_eq(p, "print")) { if (*(p + 1) == '\0' || is_eq(p, "print")) {
return POSTS_REPORT(new print_xacts(*this, HANDLED(raw))); return POSTS_REPORTER(new print_xacts(*this, HANDLED(raw)));
} }
else if (is_eq(p, "prices")) { else if (is_eq(p, "prices")) {
return POSTS_REPORT_(&report_t::commodities_report, return FORMATTED_COMMODITIES_REPORTER(prices_format_);
new format_posts
(*this, report_format(HANDLER(prices_format_)),
maybe_format(HANDLER(prepend_format_)),
HANDLER(prepend_width_).value.to_size_t()));
} }
else if (is_eq(p, "pricedb")) { else if (is_eq(p, "pricedb")) {
return POSTS_REPORT_(&report_t::commodities_report, return FORMATTED_COMMODITIES_REPORTER(pricedb_format_);
new format_posts
(*this, report_format(HANDLER(pricedb_format_)),
maybe_format(HANDLER(prepend_format_)),
HANDLER(prepend_width_).value.to_size_t()));
} }
else if (is_eq(p, "pricemap")) { else if (is_eq(p, "pricemap")) {
return MAKE_FUNCTOR(report_t::pricemap_command); return MAKE_FUNCTOR(report_t::pricemap_command);
} }
else if (is_eq(p, "payees")) { else if (is_eq(p, "payees")) {
return POSTS_REPORT(new report_payees(*this)); return POSTS_REPORTER(new report_payees(*this));
} }
break; break;
case 'r': case 'r':
if (*(p + 1) == '\0' || is_eq(p, "reg") || is_eq(p, "register")) { if (*(p + 1) == '\0' || is_eq(p, "reg") || is_eq(p, "register")) {
return POSTS_REPORT(new format_posts return FORMATTED_POSTS_REPORTER(register_format_);
(*this, report_format(HANDLER(register_format_)),
maybe_format(HANDLER(prepend_format_)),
HANDLER(prepend_width_).value.to_size_t()));
} }
else if (is_eq(p, "reload")) { else if (is_eq(p, "reload")) {
return MAKE_FUNCTOR(report_t::reload_command); return MAKE_FUNCTOR(report_t::reload_command);
@ -1545,7 +1541,7 @@ expr_t::ptr_op_t report_t::lookup(const symbol_t::kind_t kind,
if (is_eq(p, "xact")) if (is_eq(p, "xact"))
return WRAP_FUNCTOR(xact_command); return WRAP_FUNCTOR(xact_command);
else if (is_eq(p, "xml")) else if (is_eq(p, "xml"))
return POSTS_REPORT(new format_xml(*this)); return POSTS_REPORTER(new format_xml(*this));
break; break;
} }
break; break;
@ -1568,8 +1564,8 @@ expr_t::ptr_op_t report_t::lookup(const symbol_t::kind_t kind,
break; break;
case 'g': case 'g':
if (is_eq(p, "generate")) if (is_eq(p, "generate"))
return POSTS_REPORT_(&report_t::generate_report, return POSTS_REPORTER_(&report_t::generate_report,
new print_xacts(*this)); new print_xacts(*this));
break; break;
case 'p': case 'p':
if (is_eq(p, "parse")) if (is_eq(p, "parse"))

View file

@ -353,12 +353,16 @@ public:
* Option handlers * Option handlers
*/ */
OPTION__(report_t, abbrev_len_, OPTION__
CTOR(report_t, abbrev_len_) { on_with(none, 2L); }); (report_t, abbrev_len_,
CTOR(report_t, abbrev_len_) {
on(none, "2");
});
OPTION(report_t, account_); OPTION(report_t, account_);
OPTION_(report_t, actual, DO() { // -L OPTION_(report_t, actual, DO() { // -L
parent->HANDLER(limit_).on(string("--actual"), "actual"); OTHER(limit_).on(whence, "actual");
}); });
OPTION_(report_t, add_budget, DO() { OPTION_(report_t, add_budget, DO() {
@ -368,12 +372,8 @@ public:
OPTION__ OPTION__
(report_t, amount_, // -t (report_t, amount_, // -t
DECL1(report_t, amount_, merged_expr_t, expr, ("amount_expr", "amount")) {} DECL1(report_t, amount_, merged_expr_t, expr, ("amount_expr", "amount")) {}
void set_expr(const optional<string>& whence, const string& str) { DO_(str) {
expr.append(str); expr.append(str);
on(whence, str);
}
DO_(args) {
set_expr(args.get<string>(0), args.get<string>(1));
}); });
OPTION(report_t, amount_data); // -j OPTION(report_t, amount_data); // -j
@ -381,216 +381,204 @@ public:
OPTION(report_t, auto_match); OPTION(report_t, auto_match);
OPTION_(report_t, average, DO() { // -A OPTION_(report_t, average, DO() { // -A
parent->HANDLER(display_total_) OTHER(display_total_)
.set_expr(string("--average"), "count>0?(display_total/count):0"); .on(whence, "count>0?(display_total/count):0");
}); });
OPTION__(report_t, balance_format_, CTOR(report_t, balance_format_) { OPTION__
on(none, (report_t, balance_format_,
"%(ansify_if(" CTOR(report_t, balance_format_) {
" justify(scrub(display_total), 20, 20 + prepend_width, true, color)," on(none,
" bold if should_bold))" "%(ansify_if("
" %(!options.flat ? depth_spacer : \"\")" " justify(scrub(display_total), 20,"
"%-(ansify_if(" " 20 + int(prepend_width), true, color),"
" ansify_if(partial_account(options.flat), blue if color)," " bold if should_bold))"
" bold if should_bold))\n%/" " %(!options.flat ? depth_spacer : \"\")"
"%$1\n%/" "%-(ansify_if("
"%(prepend_width ? \" \" * prepend_width : \"\")" " ansify_if(partial_account(options.flat), blue if color),"
"--------------------\n"); " bold if should_bold))\n%/"
}); "%$1\n%/"
"%(prepend_width ? \" \" * int(prepend_width) : \"\")"
"--------------------\n");
});
OPTION(report_t, base); OPTION(report_t, base);
OPTION_(report_t, basis, DO() { // -B OPTION_(report_t, basis, DO() { // -B
parent->HANDLER(revalued).on_only(string("--basis")); OTHER(revalued).on(whence);
parent->HANDLER(amount_).expr.set_base_expr("rounded(cost)"); OTHER(amount_).expr.set_base_expr("rounded(cost)");
}); });
OPTION_(report_t, begin_, DO_(args) { // -b OPTION_(report_t, begin_, DO_(str) { // -b
date_interval_t interval(args.get<string>(1)); date_interval_t interval(str);
optional<date_t> begin = interval.begin(); if (optional<date_t> begin = interval.begin()) {
if (! begin) string predicate = "date>=[" + to_iso_extended_string(*begin) + "]";
OTHER(limit_).on(whence, predicate);
} else {
throw_(std::invalid_argument, throw_(std::invalid_argument,
_("Could not determine beginning of period '%1'") _("Could not determine beginning of period '%1'") << str);
<< args.get<string>(1)); }
string predicate = "date>=[" + to_iso_extended_string(*begin) + "]";
parent->HANDLER(limit_).on(string("--begin"), predicate);
}); });
OPTION__ OPTION_
(report_t, bold_if_, (report_t, bold_if_,
expr_t expr; expr_t expr;
CTOR(report_t, bold_if_) {} DO_(str) {
void set_expr(const optional<string>& whence, const string& str) {
expr = str; expr = str;
on(whence, str);
}
DO_(args) {
set_expr(args.get<string>(0), args.get<string>(1));
}); });
OPTION_(report_t, budget, DO() { OPTION_(report_t, budget, DO() {
parent->budget_flags |= BUDGET_BUDGETED; parent->budget_flags |= BUDGET_BUDGETED;
}); });
OPTION__(report_t, budget_format_, CTOR(report_t, budget_format_) { OPTION__
on(none, (report_t, budget_format_,
"%(justify(scrub(get_at(display_total, 0)), 12, -1, true, color))" CTOR(report_t, budget_format_) {
" %(justify(-scrub(get_at(display_total, 1)), 12, " on(none,
" 12 + 1 + 12, true, color))" "%(justify(scrub(get_at(display_total, 0)), 12, -1, true, color))"
" %(justify(scrub(get_at(display_total, 1) + " " %(justify(-scrub(get_at(display_total, 1)), 12, "
" get_at(display_total, 0)), 12, " " 12 + 1 + 12, true, color))"
" 12 + 1 + 12 + 1 + 12, true, color))" " %(justify(scrub(get_at(display_total, 1) + "
" %(ansify_if(" " get_at(display_total, 0)), 12, "
" justify((get_at(display_total, 1) ? " " 12 + 1 + 12 + 1 + 12, true, color))"
" (100% * scrub(get_at(display_total, 0))) / " " %(ansify_if("
" -scrub(get_at(display_total, 1)) : 0), " " justify((get_at(display_total, 1) ? "
" 5, -1, true, false)," " (100% * scrub(get_at(display_total, 0))) / "
" magenta if (color and get_at(display_total, 1) and " " -scrub(get_at(display_total, 1)) : 0), "
" (abs(quantity(scrub(get_at(display_total, 0))) / " " 5, -1, true, false),"
" quantity(scrub(get_at(display_total, 1)))) >= 1))))" " magenta if (color and get_at(display_total, 1) and "
" %(!options.flat ? depth_spacer : \"\")" " (abs(quantity(scrub(get_at(display_total, 0))) / "
"%-(ansify_if(partial_account(options.flat), blue if color))\n" " quantity(scrub(get_at(display_total, 1)))) >= 1))))"
"%/%$1 %$2 %$3 %$4\n%/" " %(!options.flat ? depth_spacer : \"\")"
"%(prepend_width ? \" \" * prepend_width : \"\")" "%-(ansify_if(partial_account(options.flat), blue if color))\n"
"------------ ------------ ------------ -----\n"); "%/%$1 %$2 %$3 %$4\n%/"
}); "%(prepend_width ? \" \" * int(prepend_width) : \"\")"
"------------ ------------ ------------ -----\n");
});
OPTION(report_t, by_payee); // -P OPTION(report_t, by_payee); // -P
OPTION_(report_t, cleared, DO() { // -C OPTION_(report_t, cleared, DO() { // -C
parent->HANDLER(limit_).on(string("--cleared"), "cleared"); OTHER(limit_).on(whence, "cleared");
}); });
OPTION__(report_t, cleared_format_, CTOR(report_t, cleared_format_) { OPTION__
on(none, (report_t, cleared_format_,
"%(justify(scrub(get_at(display_total, 0)), 16, 16 + prepend_width, " CTOR(report_t, cleared_format_) {
" true, color)) %(justify(scrub(get_at(display_total, 1)), 18, " on(none,
" 36 + prepend_width, true, color))" "%(justify(scrub(get_at(display_total, 0)), 16, 16 + int(prepend_width), "
" %(latest_cleared ? format_date(latest_cleared) : \" \")" " true, color)) %(justify(scrub(get_at(display_total, 1)), 18, "
" %(!options.flat ? depth_spacer : \"\")" " 36 + int(prepend_width), true, color))"
"%-(ansify_if(partial_account(options.flat), blue if color))\n%/" " %(latest_cleared ? format_date(latest_cleared) : \" \")"
"%$1 %$2 %$3\n%/" " %(!options.flat ? depth_spacer : \"\")"
"%(prepend_width ? \" \" * prepend_width : \"\")" "%-(ansify_if(partial_account(options.flat), blue if color))\n%/"
"---------------- ---------------- ---------\n"); "%$1 %$2 %$3\n%/"
}); "%(prepend_width ? \" \" * int(prepend_width) : \"\")"
"---------------- ---------------- ---------\n");
});
OPTION(report_t, color); OPTION(report_t, color);
OPTION_(report_t, collapse, DO() { // -n OPTION_(report_t, collapse, DO() { // -n
// Make sure that balance reports are collapsed too, but only apply it // Make sure that balance reports are collapsed too, but only apply it
// to account xacts // to account xacts
parent->HANDLER(display_).on(string("--collapse"), "post|depth<=1"); OTHER(display_).on(whence, "post|depth<=1");
}); });
OPTION_(report_t, collapse_if_zero, DO() { OPTION_(report_t, collapse_if_zero, DO() {
parent->HANDLER(collapse).on_only(string("--collapse-if-zero")); OTHER(collapse).on(whence);
}); });
OPTION(report_t, columns_); OPTION(report_t, columns_);
OPTION(report_t, count); OPTION(report_t, count);
OPTION__(report_t, csv_format_, CTOR(report_t, csv_format_) { OPTION__
on(none, (report_t, csv_format_,
"%(quoted(date))," CTOR(report_t, csv_format_) {
"%(quoted(code))," on(none,
"%(quoted(payee))," "%(quoted(date)),"
"%(quoted(display_account))," "%(quoted(code)),"
"%(quoted(commodity))," "%(quoted(payee)),"
"%(quoted(quantity(scrub(display_amount))))," "%(quoted(display_account)),"
"%(quoted(cleared ? \"*\" : (pending ? \"!\" : \"\")))," "%(quoted(commodity)),"
"%(quoted(join(note | xact.note)))\n"); "%(quoted(quantity(scrub(display_amount)))),"
}); "%(quoted(cleared ? \"*\" : (pending ? \"!\" : \"\"))),"
"%(quoted(join(note | xact.note)))\n");
});
OPTION_(report_t, current, DO() { // -c OPTION_(report_t, current, DO() { // -c
parent->HANDLER(limit_).on(string("--current"), "date<=today"); OTHER(limit_).on(whence, "date<=today");
}); });
OPTION_(report_t, daily, DO() { // -D OPTION_(report_t, daily, DO() { // -D
parent->HANDLER(period_).on(string("--daily"), "daily"); OTHER(period_).on(whence, "daily");
}); });
OPTION(report_t, date_); OPTION(report_t, date_);
OPTION(report_t, date_format_); OPTION(report_t, date_format_);
OPTION(report_t, datetime_format_); OPTION(report_t, datetime_format_);
OPTION_(report_t, depth_, DO_(args) { OPTION_(report_t, depth_, DO_(str) {
parent->HANDLER(display_) OTHER(display_).on(whence, string("depth<=") + str);
.on(string("--depth"), string("depth<=") + args.get<string>(1));
}); });
OPTION_(report_t, deviation, DO() { OPTION_(report_t, deviation, DO() {
parent->HANDLER(display_total_) OTHER(display_total_)
.set_expr(string("--deviation"), "display_amount-display_total"); .on(whence, "display_amount-display_total");
}); });
OPTION__ OPTION_
(report_t, display_, // -d (report_t, display_,
CTOR(report_t, display_) {} DO_(str) { // -d
virtual void on_with(const optional<string>& whence, const value_t& text) { if (handled)
if (! handled) value = string("(") + value + ")&(" + str + ")";
option_t<report_t>::on_with(whence, text);
else
option_t<report_t>::on_with(whence,
string_value(string("(") + str() + ")&(" +
text.as_string() + ")"));
}); });
OPTION__ OPTION__
(report_t, display_amount_, (report_t, display_amount_,
DECL1(report_t, display_amount_, merged_expr_t, expr, DECL1(report_t, display_amount_, merged_expr_t, expr,
("display_amount", "amount_expr")) {} ("display_amount", "amount_expr")) {}
void set_expr(const optional<string>& whence, const string& str) { DO_(str) {
expr.append(str); expr.append(str);
on(whence, str);
}
DO_(args) {
set_expr(args.get<string>(0), args.get<string>(1));
}); });
OPTION__ OPTION__
(report_t, display_total_, (report_t, display_total_,
DECL1(report_t, display_total_, merged_expr_t, expr, DECL1(report_t, display_total_, merged_expr_t, expr,
("display_total", "total_expr")) {} ("display_total", "total_expr")) {}
void set_expr(const optional<string>& whence, const string& str) { DO_(str) {
expr.append(str); expr.append(str);
on(whence, str);
}
DO_(args) {
set_expr(args.get<string>(0), args.get<string>(1));
}); });
OPTION(report_t, dow); OPTION(report_t, dow);
OPTION(report_t, aux_date); OPTION(report_t, aux_date);
OPTION(report_t, empty); // -E OPTION(report_t, empty); // -E
OPTION_(report_t, end_, DO_(args) { // -e OPTION_(report_t, end_, DO_(str) { // -e
date_interval_t interval(args.get<string>(1));
// Use begin() here so that if the user says --end=2008, we end on // Use begin() here so that if the user says --end=2008, we end on
// 2008/01/01 instead of 2009/01/01 (which is what end() would // 2008/01/01 instead of 2009/01/01 (which is what end() would
// return). // return).
optional<date_t> end = interval.begin(); date_interval_t interval(str);
if (! end) if (optional<date_t> end = interval.begin()) {
string predicate = "date<[" + to_iso_extended_string(*end) + "]";
OTHER(limit_).on(whence, predicate);
parent->terminus = datetime_t(*end);
} else {
throw_(std::invalid_argument, throw_(std::invalid_argument,
_("Could not determine end of period '%1'") _("Could not determine end of period '%1'")
<< args.get<string>(1)); << str);
}
string predicate = "date<[" + to_iso_extended_string(*end) + "]";
parent->HANDLER(limit_).on(string("--end"), predicate);
parent->terminus = datetime_t(*end);
}); });
OPTION(report_t, equity); OPTION(report_t, equity);
OPTION(report_t, exact); OPTION(report_t, exact);
OPTION_(report_t, exchange_, DO_(args) { // -X OPTION_(report_t, exchange_, DO_() { // -X
on_with(args.get<string>(0), args[1]); // Using -X implies -V. The main difference is that now
call_scope_t no_args(*parent); // HANDLER(exchange_) contains the name of a commodity, which
no_args.push_back(args[0]); // is accessed via the "exchange" value expression function.
parent->HANDLER(market).parent = parent; OTHER(market).on(whence);
parent->HANDLER(market).handler(no_args);
}); });
OPTION(report_t, flat); OPTION(report_t, flat);
@ -601,74 +589,65 @@ public:
OPTION(report_t, format_); // -F OPTION(report_t, format_); // -F
OPTION_(report_t, gain, DO() { // -G OPTION_(report_t, gain, DO() { // -G
parent->HANDLER(revalued).on_only(string("--gain")); OTHER(revalued).on(whence);
parent->HANDLER(amount_).expr.set_base_expr("(amount, cost)"); OTHER(amount_).expr.set_base_expr("(amount, cost)");
parent->HANDLER(total_).expr.set_base_expr("total"); OTHER(total_).expr.set_base_expr("total");
// Since we are displaying the amounts of revalued postings, they // Since we are displaying the amounts of revalued postings, they
// will end up being composite totals, and hence a pair of pairs. // will end up being composite totals, and hence a pair of pairs.
parent->HANDLER(display_amount_) OTHER(display_amount_)
.set_expr(string("--gain"), .on(whence,
"use_direct_amount ? amount :" "use_direct_amount ? amount :"
" (is_seq(get_at(amount_expr, 0)) ?" " (is_seq(get_at(amount_expr, 0)) ?"
" get_at(get_at(amount_expr, 0), 0) :" " get_at(get_at(amount_expr, 0), 0) :"
" market(get_at(amount_expr, 0), value_date, exchange)" " market(get_at(amount_expr, 0), value_date, exchange)"
" - get_at(amount_expr, 1))"); " - get_at(amount_expr, 1))");
parent->HANDLER(revalued_total_) OTHER(revalued_total_)
.set_expr(string("--gain"), .on(whence,
"(market(get_at(total_expr, 0), value_date, exchange), " "(market(get_at(total_expr, 0), value_date, exchange), "
"get_at(total_expr, 1))"); "get_at(total_expr, 1))");
parent->HANDLER(display_total_) OTHER(display_total_)
.set_expr(string("--gain"), .on(whence,
"use_direct_amount ? total_expr :" "use_direct_amount ? total_expr :"
" market(get_at(total_expr, 0), value_date, exchange)" " market(get_at(total_expr, 0), value_date, exchange)"
" - get_at(total_expr, 1)"); " - get_at(total_expr, 1)");
}); });
OPTION(report_t, generated); OPTION(report_t, generated);
OPTION__ OPTION_
(report_t, group_by_, (report_t, group_by_,
expr_t expr; expr_t expr;
CTOR(report_t, group_by_) {} DO_(str) {
void set_expr(const optional<string>& whence, const string& str) {
expr = str; expr = str;
on(whence, str);
}
DO_(args) {
set_expr(args.get<string>(0), args.get<string>(1));
}); });
OPTION__(report_t, group_title_format_, CTOR(report_t, group_title_format_) { OPTION__
on(none, "%(value)\n"); (report_t, group_title_format_,
}); CTOR(report_t, group_title_format_) {
on(none, "%(value)\n");
});
OPTION(report_t, head_); OPTION(report_t, head_);
OPTION_(report_t, historical, DO() { // -H OPTION_(report_t, historical, DO() { // -H
parent->HANDLER(amount_) OTHER(amount_)
.set_expr(string("--historical"), .on(whence, "nail_down(amount_expr, "
"nail_down(amount_expr, (s,d,t -> market(s,value_date,t)))"); "market(amount_expr, value_date, exchange))");
}); });
OPTION(report_t, inject_); OPTION(report_t, inject_);
OPTION_(report_t, invert, DO() { OPTION_(report_t, invert, DO() {
parent->HANDLER(amount_).set_expr(string("--invert"), "-amount"); OTHER(amount_).on(whence, "-amount");
}); });
OPTION__ OPTION_
(report_t, limit_, // -l (report_t, limit_,
CTOR(report_t, limit_) {} DO_(str) { // -l
virtual void on_with(const optional<string>& whence, const value_t& text) { if (handled)
if (! handled) value = string("(") + value + ")&(" + str + ")";
option_t<report_t>::on_with(whence, text);
else
option_t<report_t>::on_with(whence,
string_value(string("(") + str() + ")&(" +
text.as_string() + ")"));
}); });
OPTION(report_t, lot_dates); OPTION(report_t, lot_dates);
@ -678,49 +657,44 @@ public:
OPTION(report_t, lots_actual); OPTION(report_t, lots_actual);
OPTION_(report_t, market, DO() { // -V OPTION_(report_t, market, DO() { // -V
parent->HANDLER(revalued).on_only(string("--market")); OTHER(revalued).on(whence);
parent->HANDLER(display_amount_)
.set_expr(string("--market"), OTHER(display_amount_)
"market(display_amount, value_date, exchange)"); .on(whence, "market(display_amount, value_date, exchange)");
parent->HANDLER(display_total_) OTHER(display_total_)
.set_expr(string("--market"), .on(whence, "market(display_total, value_date, exchange)");
"market(display_total, value_date, exchange)");
}); });
OPTION(report_t, meta_); OPTION(report_t, meta_);
OPTION_(report_t, monthly, DO() { // -M OPTION_(report_t, monthly, DO() { // -M
parent->HANDLER(period_).on(string("--monthly"), "monthly"); OTHER(period_).on(whence, "monthly");
}); });
OPTION_(report_t, no_color, DO() { OPTION_(report_t, no_color, DO() {
parent->HANDLER(color).off(); OTHER(color).off();
}); });
OPTION(report_t, no_rounding); OPTION(report_t, no_rounding);
OPTION(report_t, no_titles); OPTION(report_t, no_titles);
OPTION(report_t, no_total); OPTION(report_t, no_total);
OPTION_(report_t, now_, DO_(args) { OPTION_(report_t, now_, DO_(str) {
date_interval_t interval(args.get<string>(1)); date_interval_t interval(str);
optional<date_t> begin = interval.begin(); if (optional<date_t> begin = interval.begin()) {
if (! begin) ledger::epoch = parent->terminus = datetime_t(*begin);
} else {
throw_(std::invalid_argument, throw_(std::invalid_argument,
_("Could not determine beginning of period '%1'") _("Could not determine beginning of period '%1'")
<< args.get<string>(1)); << str);
ledger::epoch = parent->terminus = datetime_t(*begin); }
}); });
OPTION__ OPTION_
(report_t, only_, (report_t, only_,
CTOR(report_t, only_) {} DO_(str) {
virtual void on_with(const optional<string>& whence, const value_t& text) { if (handled)
if (! handled) value = string("(") + value + ")&(" + str + ")";
option_t<report_t>::on_with(whence, text);
else
option_t<report_t>::on_with(whence,
string_value(string("(") + str() + ")&(" +
text.as_string() + ")"));
}); });
OPTION(report_t, output_); // -o OPTION(report_t, output_); // -o
@ -741,178 +715,162 @@ public:
setenv("LESS", "-FRSX", 0); // don't overwrite setenv("LESS", "-FRSX", 0); // don't overwrite
} }
} }
}
virtual void on_with(const optional<string>& whence, const value_t& text) {
string cmd(text.to_string());
if (cmd == "" || cmd == "false" || cmd == "off" ||
cmd == "none" || cmd == "no" || cmd == "disable")
option_t<report_t>::off();
else
option_t<report_t>::on_with(whence, text);
}); });
#else // HAVE_ISATTY #else // HAVE_ISATTY
OPTION__ OPTION(report_t, pager_);
(report_t, pager_,
CTOR(report_t, pager_) {
}
virtual void on_with(const optional<string>& whence, const value_t& text) {
string cmd(text.to_string());
if (cmd == "" || cmd == "false" || cmd == "off" ||
cmd == "none" || cmd == "no" || cmd == "disable")
option_t<report_t>::off();
else
option_t<report_t>::on_with(whence, text);
});
#endif // HAVE_ISATTY #endif // HAVE_ISATTY
OPTION_(report_t, no_pager, DO() {
OTHER(pager_).off();
});
OPTION(report_t, payee_); OPTION(report_t, payee_);
OPTION_(report_t, pending, DO() { // -C OPTION_(report_t, pending, DO() { // -C
parent->HANDLER(limit_).on(string("--pending"), "pending"); OTHER(limit_).on(whence, "pending");
}); });
OPTION_(report_t, percent, DO() { // -% OPTION_(report_t, percent, DO() { // -%
parent->HANDLER(total_) OTHER(total_)
.set_expr(string("--percent"), .on(whence,
"((is_account&parent&parent.total)?" "((is_account&parent&parent.total)?"
" percent(scrub(total), scrub(parent.total)):0)"); " percent(scrub(total), scrub(parent.total)):0)");
}); });
OPTION__ OPTION_
(report_t, period_, // -p (report_t, period_,
CTOR(report_t, period_) {} DO_(str) { // -p
virtual void on_with(const optional<string>& whence, const value_t& text) { if (handled)
if (! handled) value += string(" ") + str;
option_t<report_t>::on_with(whence, text);
else
option_t<report_t>::on_with(whence,
string_value(text.as_string() + " " + str()));
}); });
OPTION(report_t, pivot_); OPTION(report_t, pivot_);
OPTION__(report_t, plot_amount_format_, CTOR(report_t, plot_amount_format_) { OPTION__
on(none, (report_t, plot_amount_format_,
"%(format_date(date, \"%Y-%m-%d\")) %(quantity(scrub(display_amount)))\n"); CTOR(report_t, plot_amount_format_) {
}); on(none,
"%(format_date(date, \"%Y-%m-%d\")) %(quantity(scrub(display_amount)))\n");
});
OPTION__(report_t, plot_total_format_, CTOR(report_t, plot_total_format_) { OPTION__
on(none, (report_t, plot_total_format_,
"%(format_date(date, \"%Y-%m-%d\")) %(quantity(scrub(display_total)))\n"); CTOR(report_t, plot_total_format_) {
}); on(none,
"%(format_date(date, \"%Y-%m-%d\")) %(quantity(scrub(display_total)))\n");
});
OPTION(report_t, prepend_format_); OPTION(report_t, prepend_format_);
OPTION_(report_t, prepend_width_, DO_(args) { OPTION(report_t, prepend_width_);
value = args.get<long>(1);
});
OPTION_(report_t, price, DO() { // -I OPTION_(report_t, price, DO() { // -I
parent->HANDLER(amount_).expr.set_base_expr("price"); OTHER(amount_).expr.set_base_expr("price");
}); });
OPTION__(report_t, prices_format_, CTOR(report_t, prices_format_) { OPTION__
on(none, (report_t, prices_format_,
"%(date) %-8(display_account) %(justify(scrub(display_amount), 12, " CTOR(report_t, prices_format_) {
" 2 + 9 + 8 + 12, true, color))\n"); on(none,
}); "%(date) %-8(display_account) %(justify(scrub(display_amount), 12, "
" 2 + 9 + 8 + 12, true, color))\n");
});
OPTION__(report_t, pricedb_format_, CTOR(report_t, pricedb_format_) { OPTION__
on(none, (report_t, pricedb_format_,
"P %(datetime) %(display_account) %(scrub(display_amount))\n"); CTOR(report_t, pricedb_format_) {
}); on(none,
"P %(datetime) %(display_account) %(scrub(display_amount))\n");
});
OPTION(report_t, primary_date); OPTION(report_t, primary_date);
OPTION_(report_t, quantity, DO() { // -O OPTION_(report_t, quantity, DO() { // -O
parent->HANDLER(revalued).off(); OTHER(revalued).off();
parent->HANDLER(amount_).expr.set_base_expr("amount");
parent->HANDLER(total_).expr.set_base_expr("total"); OTHER(amount_).expr.set_base_expr("amount");
OTHER(total_).expr.set_base_expr("total");
}); });
OPTION_(report_t, quarterly, DO() { OPTION_(report_t, quarterly, DO() {
parent->HANDLER(period_).on(string("--quarterly"), "quarterly"); OTHER(period_).on(whence, "quarterly");
}); });
OPTION(report_t, raw); OPTION(report_t, raw);
OPTION_(report_t, real, DO() { // -R OPTION_(report_t, real, DO() { // -R
parent->HANDLER(limit_).on(string("--real"), "real"); OTHER(limit_).on(whence, "real");
}); });
OPTION__(report_t, register_format_, CTOR(report_t, register_format_) { OPTION__
on(none, (report_t, register_format_,
"%(ansify_if(" CTOR(report_t, register_format_) {
" ansify_if(justify(format_date(date), date_width)," on(none,
" green if color and date > today)," "%(ansify_if("
" bold if should_bold))" " ansify_if(justify(format_date(date), int(date_width)),"
" %(ansify_if(" " green if color and date > today),"
" ansify_if(justify(truncated(payee, payee_width), payee_width), " " bold if should_bold))"
" bold if color and !cleared and actual)," " %(ansify_if("
" bold if should_bold))" " ansify_if(justify(truncated(payee, int(payee_width)), int(payee_width)), "
" %(ansify_if(" " bold if color and !cleared and actual),"
" ansify_if(justify(truncated(display_account, account_width, " " bold if should_bold))"
" abbrev_len), account_width)," " %(ansify_if("
" blue if color)," " ansify_if(justify(truncated(display_account, int(account_width), "
" bold if should_bold))" " abbrev_len), int(account_width)),"
" %(ansify_if(" " blue if color),"
" justify(scrub(display_amount), amount_width, " " bold if should_bold))"
" 3 + meta_width + date_width + payee_width" " %(ansify_if("
" + account_width + amount_width + prepend_width," " justify(scrub(display_amount), int(amount_width), "
" true, color)," " 3 + int(meta_width) + int(date_width) + int(payee_width)"
" bold if should_bold))" " + int(account_width) + int(amount_width) + int(prepend_width),"
" %(ansify_if(" " true, color),"
" justify(scrub(display_total), total_width, " " bold if should_bold))"
" 4 + meta_width + date_width + payee_width" " %(ansify_if("
" + account_width + amount_width + total_width" " justify(scrub(display_total), int(total_width), "
" + prepend_width, true, color)," " 4 + int(meta_width) + int(date_width) + int(payee_width)"
" bold if should_bold))\n%/" " + int(account_width) + int(amount_width) + int(total_width)"
"%(justify(\" \", date_width))" " + int(prepend_width), true, color),"
" %(ansify_if(" " bold if should_bold))\n%/"
" justify(truncated(has_tag(\"Payee\") ? payee : \" \", " "%(justify(\" \", int(date_width)))"
" payee_width), payee_width)," " %(ansify_if("
" bold if should_bold))" " justify(truncated(has_tag(\"Payee\") ? payee : \" \", "
" %$3 %$4 %$5\n"); " int(payee_width)), int(payee_width)),"
}); " bold if should_bold))"
" %$3 %$4 %$5\n");
});
OPTION(report_t, related); // -r OPTION(report_t, related); // -r
OPTION_(report_t, related_all, DO() { OPTION_(report_t, related_all, DO() {
parent->HANDLER(related).on_only(string("--related-all")); OTHER(related).on(whence);
}); });
OPTION(report_t, revalued); OPTION(report_t, revalued);
OPTION(report_t, revalued_only); OPTION(report_t, revalued_only);
OPTION__ OPTION_
(report_t, revalued_total_, (report_t, revalued_total_,
expr_t expr; expr_t expr;
CTOR(report_t, revalued_total_) {} DO_(str) {
void set_expr(const optional<string>& whence, const string& str) {
expr = str; expr = str;
on(whence, str);
}
DO_(args) {
set_expr(args.get<string>(0), args.get<string>(1));
}); });
OPTION(report_t, rich_data); OPTION(report_t, rich_data);
OPTION(report_t, seed_); OPTION(report_t, seed_);
OPTION_(report_t, sort_, DO_(args) { // -S OPTION_(report_t, sort_, DO_(str) { // -S
on_with(args.get<string>(0), args[1]); OTHER(sort_xacts_).off();
parent->HANDLER(sort_xacts_).off(); OTHER(sort_all_).off();
parent->HANDLER(sort_all_).off();
}); });
OPTION_(report_t, sort_all_, DO_(args) { OPTION_(report_t, sort_all_, DO_(str) {
parent->HANDLER(sort_).on_with(string("--sort-all"), args[1]); OTHER(sort_).on(whence, str);
parent->HANDLER(sort_xacts_).off(); OTHER(sort_xacts_).off();
}); });
OPTION_(report_t, sort_xacts_, DO_(args) { OPTION_(report_t, sort_xacts_, DO_(str) {
parent->HANDLER(sort_).on_with(string("--sort-xacts"), args[1]); OTHER(sort_).on(whence, str);
parent->HANDLER(sort_all_).off(); OTHER(sort_all_).off();
}); });
OPTION(report_t, start_of_week_); OPTION(report_t, start_of_week_);
@ -922,18 +880,13 @@ public:
OPTION__ OPTION__
(report_t, total_, // -T (report_t, total_, // -T
DECL1(report_t, total_, merged_expr_t, expr, ("total_expr", "total")) {} DECL1(report_t, total_, merged_expr_t, expr, ("total_expr", "total")) {}
void set_expr(const optional<string>& whence, const string& str) { DO_(str) {
expr.append(str); expr.append(str);
on(whence, str);
}
DO_(args) {
set_expr(args.get<string>(0), args.get<string>(1));
}); });
OPTION(report_t, total_data); // -J OPTION(report_t, total_data); // -J
OPTION_(report_t, truncate_, DO_(args) { OPTION_(report_t, truncate_, DO_(style) {
string style(args.get<string>(1));
if (style == "leading") if (style == "leading")
format_t::default_style = format_t::TRUNCATE_LEADING; format_t::default_style = format_t::TRUNCATE_LEADING;
else if (style == "middle") else if (style == "middle")
@ -951,7 +904,7 @@ public:
}); });
OPTION_(report_t, uncleared, DO() { // -U OPTION_(report_t, uncleared, DO() { // -U
parent->HANDLER(limit_).on(string("--uncleared"), "uncleared|pending"); OTHER(limit_).on(whence, "uncleared|pending");
}); });
OPTION(report_t, unrealized); OPTION(report_t, unrealized);
@ -960,48 +913,28 @@ public:
OPTION(report_t, unrealized_losses_); OPTION(report_t, unrealized_losses_);
OPTION_(report_t, unround, DO() { OPTION_(report_t, unround, DO() {
parent->HANDLER(amount_) OTHER(amount_).on(whence, "unrounded(amount_expr)");
.set_expr(string("--unround"), "unrounded(amount_expr)"); OTHER(total_).on(whence, "unrounded(total_expr)");
parent->HANDLER(total_)
.set_expr(string("--unround"), "unrounded(total_expr)");
}); });
OPTION_(report_t, weekly, DO() { // -W OPTION_(report_t, weekly, DO() { // -W
parent->HANDLER(period_).on(string("--weekly"), "weekly"); OTHER(period_).on(whence, "weekly");
}); });
OPTION_(report_t, wide, DO() { // -w OPTION_(report_t, wide, DO() { // -w
parent->HANDLER(columns_).on_with(string("--wide"), 132L); OTHER(columns_).on(whence, "132");
}); });
OPTION_(report_t, yearly, DO() { // -Y OPTION_(report_t, yearly, DO() { // -Y
parent->HANDLER(period_).on(string("--yearly"), "yearly"); OTHER(period_).on(whence, "yearly");
}); });
OPTION__(report_t, meta_width_, OPTION(report_t, meta_width_);
bool specified; OPTION(report_t, date_width_);
CTOR(report_t, meta_width_) { specified = false; } OPTION(report_t, payee_width_);
DO_(args) { value = args.get<long>(1); specified = true; }); OPTION(report_t, account_width_);
OPTION__(report_t, date_width_, OPTION(report_t, amount_width_);
bool specified; OPTION(report_t, total_width_);
CTOR(report_t, date_width_) { specified = false; }
DO_(args) { value = args.get<long>(1); specified = true; });
OPTION__(report_t, payee_width_,
bool specified;
CTOR(report_t, payee_width_) { specified = false; }
DO_(args) { value = args.get<long>(1); specified = true; });
OPTION__(report_t, account_width_,
bool specified;
CTOR(report_t, account_width_) { specified = false; }
DO_(args) { value = args.get<long>(1); specified = true; });
OPTION__(report_t, amount_width_,
bool specified;
CTOR(report_t, amount_width_) { specified = false; }
DO_(args) { value = args.get<long>(1); specified = true; });
OPTION__(report_t, total_width_,
bool specified;
CTOR(report_t, total_width_) { specified = false; }
DO_(args) { value = args.get<long>(1); specified = true; });
}; };

View file

@ -128,28 +128,24 @@ public:
OPTION__ OPTION__
(session_t, price_exp_, // -Z (session_t, price_exp_, // -Z
CTOR(session_t, price_exp_) { value = 24L * 3600L; } CTOR(session_t, price_exp_) { value = "24"; });
DO_(args) {
value = args.get<long>(1) * 60L;
});
OPTION__ OPTION__
(session_t, file_, // -f (session_t, file_, // -f
std::list<path> data_files; std::list<path> data_files;
CTOR(session_t, file_) {} CTOR(session_t, file_) {}
DO_(args) { DO_(str) {
assert(args.size() == 2);
if (parent->flush_on_next_data_file) { if (parent->flush_on_next_data_file) {
data_files.clear(); data_files.clear();
parent->flush_on_next_data_file = false; parent->flush_on_next_data_file = false;
} }
data_files.push_back(args.get<string>(1)); data_files.push_back(str);
}); });
OPTION_(session_t, input_date_format_, DO_(args) { OPTION_(session_t, input_date_format_, DO_(str) {
// This changes static variables inside times.h, which affects the basic // This changes static variables inside times.h, which affects the
// date parser. // basic date parser.
set_input_date_format(args.get<string>(1).c_str()); set_input_date_format(str.c_str());
}); });
OPTION(session_t, explicit); OPTION(session_t, explicit);

View file