summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Wiegley <johnw@newartisans.com>2009-02-05 21:18:37 -0400
committerJohn Wiegley <johnw@newartisans.com>2009-02-05 21:20:09 -0400
commit408b819c6e087593ba61e82b91dda2369ef32f62 (patch)
tree68456c86187e00355d47c5794008b8226bd000e2
parent7b24e8f8e33049fe533cce2d2d473c6122460954 (diff)
downloadfork-ledger-408b819c6e087593ba61e82b91dda2369ef32f62.tar.gz
fork-ledger-408b819c6e087593ba61e82b91dda2369ef32f62.tar.bz2
fork-ledger-408b819c6e087593ba61e82b91dda2369ef32f62.zip
Greatly simplified the way option and command handlers are defined.
-rw-r--r--src/chain.cc150
-rw-r--r--src/chain.h41
-rw-r--r--src/csv.h3
-rw-r--r--src/emacs.h3
-rw-r--r--src/filters.h4
-rw-r--r--src/global.cc83
-rw-r--r--src/global.h19
-rw-r--r--src/handler.h246
-rw-r--r--src/item.cc2
-rw-r--r--src/item.h2
-rw-r--r--src/main.cc5
-rw-r--r--src/output.cc6
-rw-r--r--src/output.h1
-rw-r--r--src/report.cc381
-rw-r--r--src/report.h403
-rw-r--r--src/session.cc1
-rw-r--r--src/session.h1
-rw-r--r--src/stream.cc2
-rw-r--r--src/textual.cc4
-rw-r--r--src/textual.h8
20 files changed, 723 insertions, 642 deletions
diff --git a/src/chain.cc b/src/chain.cc
index f79da543..4956a237 100644
--- a/src/chain.cc
+++ b/src/chain.cc
@@ -30,6 +30,7 @@
*/
#include "chain.h"
+#include "report.h"
#include "filters.h"
#include "reconcile.h"
@@ -43,14 +44,14 @@ xact_handler_ptr chain_xact_handlers(report_t& report,
xact_handler_ptr handler(base_handler);
- // format_xacts write each xact received to the
- // output stream.
+ // format_xacts write each xact received to the output stream.
if (handle_individual_xacts) {
- // truncate_entries cuts off a certain number of _entries_ from
- // being displayed. It does not affect calculation.
- if (report.head_entries || report.tail_entries)
- handler.reset(new truncate_entries(handler, report.head_entries,
- report.tail_entries));
+ // truncate_entries cuts off a certain number of _entries_ from being
+ // displayed. It does not affect calculation.
+ if (report.HANDLED(head_) || report.HANDLED(tail_))
+ handler.reset(new truncate_entries(handler,
+ report.HANDLER(head_).value.to_long(),
+ report.HANDLER(tail_).value.to_long()));
// filter_xacts will only pass through xacts matching the
// `display_predicate'.
@@ -59,15 +60,15 @@ xact_handler_ptr chain_xact_handlers(report_t& report,
(handler, item_predicate<xact_t>(report.display_predicate,
report.what_to_keep)));
- // calc_xacts computes the running total. When this
- // appears will determine, for example, whether filtered
- // xacts are included or excluded from the running total.
+ // calc_xacts computes the running total. When this appears will
+ // determine, for example, whether filtered xacts are included or excluded
+ // from the running total.
handler.reset(new calc_xacts(handler));
- // component_xacts looks for reported xact that
- // match the given `descend_expr', and then reports the
- // xacts which made up the total for that reported
- // xact.
+#if 0
+ // component_xacts looks for reported xact that match the given
+ // `descend_expr', and then reports the xacts which made up the total for
+ // that reported xact.
if (! report.descend_expr.empty()) {
std::list<std::string> descend_exprs;
@@ -90,9 +91,9 @@ xact_handler_ptr chain_xact_handlers(report_t& report,
remember_components = true;
}
- // reconcile_xacts will pass through only those
- // xacts which can be reconciled to a given balance
- // (calculated against the xacts which it receives).
+ // reconcile_xacts will pass through only those xacts which can be
+ // reconciled to a given balance (calculated against the xacts which it
+ // receives).
if (! report.reconcile_balance.empty()) {
date_t cutoff = CURRENT_DATE();
if (! report.reconcile_date.empty())
@@ -100,57 +101,54 @@ xact_handler_ptr chain_xact_handlers(report_t& report,
handler.reset(new reconcile_xacts
(handler, value_t(report.reconcile_balance), cutoff));
}
+#endif
- // filter_xacts will only pass through xacts
- // matching the `secondary_predicate'.
+ // filter_xacts will only pass through xacts matching the
+ // `secondary_predicate'.
if (! report.secondary_predicate.empty())
handler.reset(new filter_xacts
- (handler, item_predicate<xact_t>(report.secondary_predicate,
- report.what_to_keep)));
-
- // sort_xacts will sort all the xacts it sees, based
- // on the `sort_order' value expression.
- if (! report.sort_string.empty()) {
- if (report.entry_sort)
- handler.reset(new sort_entries(handler, report.sort_string));
+ (handler, item_predicate<xact_t>
+ (report.secondary_predicate, report.what_to_keep)));
+
+ // sort_xacts will sort all the xacts it sees, based on the `sort_order'
+ // value expression.
+ if (report.HANDLED(sort_)) {
+ if (report.HANDLED(sort_entries_))
+ handler.reset(new sort_entries(handler, report.HANDLER(sort_).str()));
else
- handler.reset(new sort_xacts(handler, report.sort_string));
+ handler.reset(new sort_xacts(handler, report.HANDLER(sort_).str()));
}
- // changed_value_xacts adds virtual xacts to the
- // list to account for changes in market value of commodities,
- // which otherwise would affect the running total unpredictably.
+ // changed_value_xacts adds virtual xacts to the list to account for
+ // changes in market value of commodities, which otherwise would affect
+ // the running total unpredictably.
if (report.show_revalued)
handler.reset(new changed_value_xacts(handler, report.total_expr,
report.show_revalued_only));
- // collapse_xacts causes entries with multiple xacts
- // to appear as entries with a subtotaled xact for each
- // commodity used.
- if (report.show_collapsed)
+ // collapse_xacts causes entries with multiple xacts to appear as entries
+ // with a subtotaled xact for each commodity used.
+ if (report.HANDLED(collapse))
handler.reset(new collapse_xacts(handler, report.session));
- // subtotal_xacts combines all the xacts it receives
- // into one subtotal entry, which has one xact for each
- // commodity in each account.
+ // subtotal_xacts combines all the xacts it receives into one subtotal
+ // entry, which has one xact for each commodity in each account.
//
- // period_xacts is like subtotal_xacts, but it
- // subtotals according to time periods rather than totalling
- // everything.
+ // period_xacts is like subtotal_xacts, but it subtotals according to time
+ // periods rather than totalling everything.
//
- // dow_xacts is like period_xacts, except that it
- // reports all the xacts that fall on each subsequent day
- // of the week.
- if (report.show_subtotal)
+ // dow_xacts is like period_xacts, except that it reports all the xacts
+ // that fall on each subsequent day of the week.
+ if (report.HANDLED(subtotal))
handler.reset(new subtotal_xacts(handler, remember_components));
- if (report.days_of_the_week)
+ if (report.HANDLED(dow))
handler.reset(new dow_xacts(handler, remember_components));
- else if (report.by_payee)
+ else if (report.HANDLED(by_payee))
handler.reset(new by_payee_xacts(handler, remember_components));
- // interval_xacts groups xacts together based on a
- // time period, such as weekly or monthly.
+ // interval_xacts groups xacts together based on a time period, such as
+ // weekly or monthly.
if (! report.report_period.empty()) {
handler.reset(new interval_xacts(handler, report.report_period,
remember_components));
@@ -158,27 +156,23 @@ xact_handler_ptr chain_xact_handlers(report_t& report,
}
}
- // invert_xacts inverts the value of the xacts it
- // receives.
- if (report.show_inverted)
+ // invert_xacts inverts the value of the xacts it receives.
+ if (report.HANDLED(invert))
handler.reset(new invert_xacts(handler));
- // related_xacts will pass along all xacts related
- // to the xact received. If `show_all_related' is true,
- // then all the entry's xacts are passed; meaning that if
- // one xact of an entry is to be printed, all the
- // xact for that entry will be printed.
- if (report.show_related)
- handler.reset(new related_xacts(handler, report.show_all_related));
-
- // anonymize_xacts removes all meaningful information from entry
- // payee's and account names, for the sake of creating useful bug
- // reports.
- if (report.anonymize)
+ // related_xacts will pass along all xacts related to the xact received. If
+ // the `related_all' handler is on, then all the entry's xacts are passed;
+ // meaning that if one xact of an entry is to be printed, all the xact for
+ // that entry will be printed.
+ if (report.HANDLED(related))
+ handler.reset(new related_xacts(handler, report.HANDLED(related_all)));
+
+ // anonymize_xacts removes all meaningful information from entry payee's and
+ // account names, for the sake of creating useful bug reports.
+ if (report.HANDLED(anon))
handler.reset(new anonymize_xacts(handler));
- // This filter_xacts will only pass through xacts
- // matching the `predicate'.
+ // This filter_xacts will only pass through xacts matching the `predicate'.
if (! report.predicate.empty()) {
DEBUG("report.predicate",
"Report predicate expression = " << report.predicate);
@@ -188,13 +182,12 @@ xact_handler_ptr chain_xact_handlers(report_t& report,
}
#if 0
- // budget_xacts takes a set of xacts from a data
- // file and uses them to generate "budget xacts" which
- // balance against the reported xacts.
+ // budget_xacts takes a set of xacts from a data file and uses them to
+ // generate "budget xacts" which balance against the reported xacts.
//
- // forecast_xacts is a lot like budget_xacts, except
- // that it adds entries only for the future, and does not balance
- // them against anything but the future balance.
+ // forecast_xacts is a lot like budget_xacts, except that it adds entries
+ // only for the future, and does not balance them against anything but the
+ // future balance.
if (report.budget_flags) {
budget_xacts * budget_handler = new budget_xacts(handler,
@@ -202,11 +195,10 @@ xact_handler_ptr chain_xact_handlers(report_t& report,
budget_handler->add_period_entries(journal->period_entries);
handler.reset(budget_handler);
- // Apply this before the budget handler, so that only matching
- // xacts are calculated toward the budget. The use of
- // filter_xacts above will further clean the results so
- // that no automated xacts that don't match the filter get
- // reported.
+ // Apply this before the budget handler, so that only matching xacts are
+ // calculated toward the budget. The use of filter_xacts above will
+ // further clean the results so that no automated xacts that don't match
+ // the filter get reported.
if (! report.predicate.empty())
handler.reset(new filter_xacts(handler, report.predicate));
}
@@ -222,9 +214,9 @@ xact_handler_ptr chain_xact_handlers(report_t& report,
}
#endif
- if (report.comm_as_payee)
+ if (report.HANDLED(comm_as_payee))
handler.reset(new set_comm_as_payee(handler));
- else if (report.code_as_payee)
+ else if (report.HANDLED(code_as_payee))
handler.reset(new set_code_as_payee(handler));
return handler;
diff --git a/src/chain.h b/src/chain.h
index c9199f05..c6de088f 100644
--- a/src/chain.h
+++ b/src/chain.h
@@ -46,10 +46,49 @@
#ifndef _CHAIN_H
#define _CHAIN_H
-#include "report.h"
+#include "xact.h"
+#include "account.h"
namespace ledger {
+/**
+ * @brief Brief
+ *
+ * Long.
+ */
+template <typename T>
+struct item_handler : public noncopyable
+{
+ shared_ptr<item_handler> handler;
+
+public:
+ item_handler() {
+ TRACE_CTOR(item_handler, "");
+ }
+ item_handler(shared_ptr<item_handler> _handler) : handler(_handler) {
+ TRACE_CTOR(item_handler, "shared_ptr<item_handler>");
+ }
+ virtual ~item_handler() {
+ TRACE_DTOR(item_handler);
+ }
+
+ virtual void flush() {
+ if (handler.get())
+ handler->flush();
+ }
+ virtual void operator()(T& item) {
+ if (handler.get()) {
+ check_for_signal();
+ (*handler.get())(item);
+ }
+ }
+};
+
+typedef shared_ptr<item_handler<xact_t> > xact_handler_ptr;
+typedef shared_ptr<item_handler<account_t> > acct_handler_ptr;
+
+class report_t;
+
xact_handler_ptr
chain_xact_handlers(report_t& report,
xact_handler_ptr base_handler,
diff --git a/src/csv.h b/src/csv.h
index d1bf54bb..cc565400 100644
--- a/src/csv.h
+++ b/src/csv.h
@@ -46,8 +46,7 @@
#ifndef _CSV_H
#define _CSV_H
-#include "handler.h"
-#include "format.h"
+#include "output.h"
namespace ledger {
diff --git a/src/emacs.h b/src/emacs.h
index fdb554ed..65aac7f6 100644
--- a/src/emacs.h
+++ b/src/emacs.h
@@ -46,8 +46,7 @@
#ifndef _EMACS_H
#define _EMACS_H
-#include "handler.h"
-#include "format.h"
+#include "output.h"
namespace ledger {
diff --git a/src/filters.h b/src/filters.h
index c6ae1a4d..67b650dc 100644
--- a/src/filters.h
+++ b/src/filters.h
@@ -46,9 +46,11 @@
#ifndef _FILTERS_H
#define _FILTERS_H
-#include "handler.h"
+#include "chain.h"
#include "predicate.h"
#include "entry.h"
+#include "xact.h"
+#include "account.h"
namespace ledger {
diff --git a/src/global.cc b/src/global.cc
index 9dff9aac..b04b4498 100644
--- a/src/global.cc
+++ b/src/global.cc
@@ -168,8 +168,10 @@ void global_scope_t::execute_command(strings_list args, bool at_repl)
// subprocess) and invoke the report command. The output stream is closed
// by the caller of this function.
- report().output_stream.initialize(report().output_file,
- session().pager_path);
+ report().output_stream
+ .initialize(report().HANDLER(output_) ?
+ optional<path>(path(report().HANDLER(output_).str())) :
+ optional<path>(), session().pager_path);
// Create an argument scope containing the report command's arguments, and
// then invoke the command. The bound scope causes lookups to happen
@@ -206,51 +208,42 @@ int global_scope_t::execute_command_wrapper(strings_list args, bool at_repl)
return status;
}
+namespace {
+}
+
expr_t::ptr_op_t global_scope_t::lookup(const string& name)
{
const char * p = name.c_str();
switch (*p) {
- case 'l':
- if (std::strncmp(p, "ledger_precmd_", 14) == 0) {
- p = p + 14;
- switch (*p) {
- case 'p':
- if (std::strcmp(p, "push") == 0)
- return MAKE_FUNCTOR(global_scope_t::push_report_cmd);
- else if (std::strcmp(p, "pop") == 0)
- return MAKE_FUNCTOR(global_scope_t::pop_report_cmd);
- break;
- }
- }
- break;
-
case 'o':
- if (std::strncmp(p, "opt_", 4) == 0) {
- p = p + 4;
+ if (WANT_OPT()) { p += OPT_PREFIX_LEN;
switch (*p) {
case 'd':
- if (std::strcmp(p, "debug_") == 0)
- return MAKE_FUNCTOR(global_scope_t::ignore);
+ OPT(debug_);
break;
-
case 's':
- if (std::strcmp(p, "script_") == 0)
- return MAKE_FUNCTOR(global_scope_t::option_script_);
+ OPT(script_);
break;
-
case 't':
- if (std::strcmp(p, "trace_") == 0)
- return MAKE_FUNCTOR(global_scope_t::ignore);
+ OPT(trace_);
break;
-
case 'v':
- if (! *(p + 1) || std::strcmp(p, "verbose") == 0)
- return MAKE_FUNCTOR(global_scope_t::ignore);
- else if (std::strcmp(p, "verify") == 0)
- return MAKE_FUNCTOR(global_scope_t::ignore);
+ OPT_(verbose);
+ else OPT(verify);
break;
}
}
+
+ case 'p':
+ if (WANT_PRECMD()) { p += PRECMD_PREFIX_LEN;
+ switch (*p) {
+ case 'p':
+ M_COMMAND(global_scope_t, push);
+ else M_COMMAND(global_scope_t, pop);
+ break;
+ }
+ }
+ break;
}
// If you're wondering how symbols from report() will be found, it's
@@ -342,7 +335,7 @@ void normalize_session_options(session_t& session)
function_t look_for_precommand(scope_t& scope, const string& verb)
{
- if (expr_t::ptr_op_t def = scope.lookup(string("ledger_precmd_") + verb))
+ if (expr_t::ptr_op_t def = scope.lookup(string("precmd_") + verb))
return def->as_function();
else
return function_t();
@@ -350,7 +343,7 @@ function_t look_for_precommand(scope_t& scope, const string& verb)
function_t look_for_command(scope_t& scope, const string& verb)
{
- if (expr_t::ptr_op_t def = scope.lookup(string("ledger_cmd_") + verb))
+ if (expr_t::ptr_op_t def = scope.lookup(string("cmd_") + verb))
return def->as_function();
else
return function_t();
@@ -365,18 +358,18 @@ void normalize_report_options(report_t& report, const string& verb)
// for 3.0.
if (verb == "print" || verb == "entry" || verb == "dump") {
- report.show_related = true;
- report.show_all_related = true;
+ report.HANDLER(related).on();
+ report.HANDLER(related_all).on();
}
else if (verb == "equity") {
- report.show_subtotal = true;
+ report.HANDLER(subtotal).on();
}
- else if (report.show_related) {
+ else if (report.HANDLED(related)) {
if (verb[0] == 'r') {
- report.show_inverted = true;
+ report.HANDLER(invert).on();
} else {
- report.show_subtotal = true;
- report.show_all_related = true;
+ report.HANDLER(subtotal).on();
+ report.HANDLER(related_all).on();
}
}
@@ -387,9 +380,9 @@ void normalize_report_options(report_t& report, const string& verb)
if (report.display_predicate.empty()) {
if (verb[0] == 'b') {
- if (! report.show_empty)
+ if (! report.HANDLED(empty))
report.display_predicate = "total";
- if (! report.show_subtotal) {
+ if (! report.HANDLED(subtotal)) {
if (! report.display_predicate.empty())
report.display_predicate += "&";
report.display_predicate += "depth<=1";
@@ -398,13 +391,13 @@ void normalize_report_options(report_t& report, const string& verb)
else if (verb == "equity") {
report.display_predicate = "amount_expr"; // jww (2008-08-14): ???
}
- else if (verb[0] == 'r' && ! report.show_empty) {
+ else if (verb[0] == 'r' && ! report.HANDLED(empty)) {
report.display_predicate = "amount";
}
}
- if (! report.report_period.empty() && ! report.sort_all)
- report.entry_sort = true;
+ if (! report.report_period.empty() && ! report.HANDLED(sort_all_))
+ report.HANDLER(sort_entries_).on();
}
} // namespace ledger
diff --git a/src/global.h b/src/global.h
index f47967fb..9b9805a6 100644
--- a/src/global.h
+++ b/src/global.h
@@ -48,8 +48,6 @@ class global_scope_t : public noncopyable, public scope_t
ptr_list<report_t> report_stack;
public:
- path script_file;
-
global_scope_t(char ** envp);
~global_scope_t();
@@ -81,7 +79,7 @@ public:
void execute_command(strings_list args, bool at_repl);
int execute_command_wrapper(strings_list args, bool at_repl);
- value_t push_report_cmd(call_scope_t&) {
+ value_t push_command(call_scope_t&) {
// Make a copy at position 2, because the topmost report object has an
// open output stream at this point. We want it to get popped off as
// soon as this command terminate so that the stream is closed cleanly.
@@ -89,19 +87,16 @@ public:
new report_t(report_stack.front()));
return true;
}
- value_t pop_report_cmd(call_scope_t&) {
+ value_t pop_command(call_scope_t&) {
pop_report();
return true;
}
- value_t option_script_(call_scope_t& args) {
- script_file = args[0].as_string();
- return true;
- }
-
- value_t ignore(call_scope_t&) {
- return true;
- }
+ OPTION(global_scope_t, debug_);
+ OPTION(global_scope_t, script_);
+ OPTION(global_scope_t, trace_);
+ OPTION(global_scope_t, verbose);
+ OPTION(global_scope_t, verify);
virtual expr_t::ptr_op_t lookup(const string& name);
};
diff --git a/src/handler.h b/src/handler.h
index bfb1b08f..83d801a3 100644
--- a/src/handler.h
+++ b/src/handler.h
@@ -39,54 +39,244 @@
*
* @ingroup report
*
- * @brief Brief
+ * @brief Defines a scheme for more easily handling commands and options via
+ * value expressions.
*
- * Long.
+ * The OPTION and OPTION_ macros are used to define an option handler within a
+ * scope_t derived class. The _ variant can specify a body in order to
+ * provide HELP(out) and DO() or DO_(args) methods.
+ *
+ * The other macros are used for looking up and referring to handlers,
+ * commands and functions. Typically they occur in the object's lookup
+ * method, for example:
+ *
+ * expr_t::ptr_op_t some_class_t::lookup(const string& name)
+ * {
+ * const char * p = name.c_str();
+ * switch (*p) {
+ * case 'a':
+ * METHOD(some_class_t, my_method); // looks up a method by name
+ * break;
+ *
+ * case 'c':
+ * if (WANT_CMD()) { p += CMD_PREFIX_LEN;
+ * switch (*p) {
+ * case 'a':
+ * COMMAND(args); // looks up global func named "args_command"
+ * break;
+ * }
+ * }
+ * break;
+ *
+ * case 'o':
+ * if (WANT_OPT()) { p += OPT_PREFIX_LEN;
+ * switch (*p) {
+ * case 'f':
+ * OPT(foo); // look for a handler named "foo"
+ * else OPT(foo2_); // same, but foo2 wants an argument
+ * else OPT_(foo3); // match on "foo3" or 'f'
+ * else OPT_CH(foo4_); // match only on 'f'
+ * break;
+ * }
+ * }
+ * break;
+ * }
+ *
+ * return expr_t::ptr_op_t();
+ * }
*/
#ifndef _HANDLER_H
#define _HANDLER_H
-#include "utils.h"
-#include "xact.h"
-#include "account.h"
+#include "scope.h"
namespace ledger {
-/**
- * @brief Brief
- *
- * Long.
- */
template <typename T>
-struct item_handler : public noncopyable
+class handler_t
{
- shared_ptr<item_handler> handler;
+ const char * name;
+ std::size_t name_len;
+ const char ch;
+ bool handled;
public:
- item_handler() {
- TRACE_CTOR(item_handler, "");
+ T * parent;
+ value_t value;
+
+ handler_t(const char * _name, const char _ch = '\0')
+ : name(_name), name_len(std::strlen(name)), ch(_ch),
+ handled(false), parent(NULL), value() {
+ TRACE_CTOR(handler_t, "const char *, const char");
}
- item_handler(shared_ptr<item_handler> _handler) : handler(_handler) {
- TRACE_CTOR(item_handler, "shared_ptr<item_handler>");
+ handler_t(const handler_t& other)
+ : name(other.name),
+ name_len(other.name_len),
+ ch(other.ch),
+ handled(other.handled),
+ parent(NULL),
+ value(other.value)
+ {
+ TRACE_CTOR(handler_t, "copy");
}
- virtual ~item_handler() {
- TRACE_DTOR(item_handler);
+
+ virtual ~handler_t() {
+ TRACE_DTOR(handler_t);
+ }
+
+ string desc() const {
+ std::ostringstream out;
+ if (ch)
+ out << "--" << name << " (-" << ch << ")";
+ else
+ out << "--" << name;
+ return out.str();
}
- virtual void flush() {
- if (handler.get())
- handler->flush();
+ virtual void help(std::ostream& out) {
+ out << "No help for " << desc() << "\n";
}
- virtual void operator()(T& item) {
- if (handler.get()) {
- check_for_signal();
- (*handler.get())(item);
- }
+
+ operator bool() const {
+ return handled;
+ }
+
+ string str() const {
+ assert(handled);
+ return value.as_string();
+ }
+
+ void on() {
+ handled = true;
+ }
+ void on(const string& str) {
+ handled = true;
+ value = string_value(str);
+ }
+ void on(const value_t& val) {
+ handled = true;
+ value = val;
+ }
+
+ void off() {
+ handled = false;
+ value = value_t();
+ }
+
+ virtual void handler(call_scope_t& args) {
+ if (name[name_len - 1] == '_')
+ value = args[0];
+ }
+
+ virtual value_t operator()(call_scope_t& args) {
+ handled = true;
+ handler(args);
+ return true;
}
};
-typedef shared_ptr<item_handler<xact_t> > xact_handler_ptr;
-typedef shared_ptr<item_handler<account_t> > acct_handler_ptr;
+#define BEGIN(type, name) \
+ struct name ## _handler_t : public handler_t<type>
+
+#define CTOR(type, name) \
+ name ## _handler_t() : handler_t<type>(#name)
+#define DECL1(type, name, vartype, var, value) \
+ vartype var ; \
+ name ## _handler_t() : handler_t<type>(#name), var(value)
+
+#define HELP(var) virtual void help(std::ostream& var)
+#define DO() virtual void handler(call_scope_t&)
+#define DO_(var) virtual void handler(call_scope_t& var)
+
+#define END(name) name ## _handler
+
+#define COPY_OPT(name, other) name ## _handler(other.name ## _handler)
+
+#define CALL_FUNCTOR(x) \
+ expr_t::op_t::wrap_functor(bind(&x ## _t::operator(), &x, _1))
+
+inline bool optcmp(const char * p, const char * n) {
+ // Test whether p matches n, substituting - in p for _ in n.
+ for (; *p && *n; p++, n++) {
+ if (! (*p == '-' && *n == '_' ) && *p != *n)
+ return false;
+ }
+ return *p == *n;
+}
+
+#define OPT(name) \
+ if (optcmp(p, #name)) \
+ return ((name ## _handler).parent = this, \
+ CALL_FUNCTOR(name ## _handler))
+
+#define OPT_(name) \
+ if (! *(p + 1) || (*(p + 1) == '_' && ! *(p + 2)) || \
+ optcmp(p, #name)) \
+ return ((name ## _handler).parent = this, \
+ CALL_FUNCTOR(name ## _handler))
+
+#define OPT_CH(name) \
+ if (! *(p + 1) || (*(p + 1) == '_' && ! *(p + 2))) \
+ return ((name ## _handler).parent = this, \
+ CALL_FUNCTOR(name ## _handler))
+
+#define FUNCTION(name) \
+ if (std::strcmp(p, #name) == 0) \
+ return WRAP_FUNCTOR(fn_ ## name)
+
+#define METHOD(type, name) \
+ if (std::strcmp(p, #name) == 0) \
+ return MAKE_FUNCTOR(type::fn_ ## name)
+
+#define M_COMMAND(type, name) \
+ if (std::strcmp(p, #name) == 0) \
+ return MAKE_FUNCTOR(type::name ## _command)
+
+#define COMMAND(name) \
+ if (std::strcmp(p, #name) == 0) \
+ return WRAP_FUNCTOR(name ## _command)
+
+#define HANDLER(name) name ## _handler
+#define HANDLED(name) HANDLER(name)
+
+#define OPTION(type, name) \
+ BEGIN(type, name) \
+ { \
+ CTOR(type, name) {} \
+ } \
+ END(name)
+
+#define OPTION_(type, name, body) \
+ BEGIN(type, name) \
+ { \
+ CTOR(type, name) {} \
+ body \
+ } \
+ END(name)
+
+#define OPT_PREFIX "opt_"
+#define OPT_PREFIX_LEN 4
+
+#define WANT_OPT() \
+ (std::strncmp(p, OPT_PREFIX, OPT_PREFIX_LEN) == 0)
+
+#define PRECMD_PREFIX "precmd_"
+#define PRECMD_PREFIX_LEN 7
+
+#define WANT_PRECMD() \
+ (std::strncmp(p, PRECMD_PREFIX, PRECMD_PREFIX_LEN) == 0)
+
+#define CMD_PREFIX "cmd_"
+#define CMD_PREFIX_LEN 4
+
+#define WANT_CMD() \
+ (std::strncmp(p, CMD_PREFIX, CMD_PREFIX_LEN) == 0)
+
+#define DIR_PREFIX "dir_"
+#define DIR_PREFIX_LEN 4
+
+#define WANT_DIR() \
+ (std::strncmp(p, DIR_PREFIX, DIR_PREFIX_LEN) == 0)
} // namespace ledger
diff --git a/src/item.cc b/src/item.cc
index a4e2f2f1..6be3bae3 100644
--- a/src/item.cc
+++ b/src/item.cc
@@ -33,8 +33,6 @@
namespace ledger {
-bool item_t::use_effective_date = false;
-
bool item_t::has_tag(const string& tag) const
{
if (! metadata)
diff --git a/src/item.h b/src/item.h
index b209b76c..a301b863 100644
--- a/src/item.h
+++ b/src/item.h
@@ -80,8 +80,6 @@ public:
istream_pos_type end_pos;
std::size_t end_line;
- static bool use_effective_date;
-
item_t(flags_t _flags = ITEM_NORMAL, const optional<string>& _note = none)
: supports_flags<>(_flags), _state(UNCLEARED), note(_note),
beg_pos(0), beg_line(0), end_pos(0), end_line(0)
diff --git a/src/main.cc b/src/main.cc
index c8192082..72d84421 100644
--- a/src/main.cc
+++ b/src/main.cc
@@ -90,14 +90,13 @@ int main(int argc, char * argv[], char * envp[])
args = read_command_arguments(bound_scope, args);
- if (! global_scope->script_file.empty() &&
- exists(global_scope->script_file)) {
+ if (global_scope->HANDLED(script_)) {
// Ledger is being invoked as a script command interpreter
global_scope->read_journal_files();
status = 0;
- ifstream in(global_scope->script_file);
+ ifstream in(global_scope->HANDLER(script_).str());
while (status == 0 && ! in.eof()) {
char line[1024];
in.getline(line, 1023);
diff --git a/src/output.cc b/src/output.cc
index da1f4bc5..a0db92b6 100644
--- a/src/output.cc
+++ b/src/output.cc
@@ -159,7 +159,7 @@ void format_accounts::flush()
account_t::xdata_t& xdata(report.session.master->xdata());
- if (! report.show_collapsed && xdata.total) {
+ if (! report.HANDLED(collapse) && xdata.total) {
out << "--------------------\n";
xdata.value = xdata.total;
bind_scope_t bound_scope(report, *report.session.master);
@@ -201,11 +201,11 @@ bool format_accounts::disp_subaccounts_p(account_t& account,
bind_scope_t bound_scope(report, *pair.second);
call_scope_t args(bound_scope);
- result = report.get_total_expr(args);
+ result = report.fn_total_expr(args);
if (! computed) {
bind_scope_t account_scope(report, account);
call_scope_t args(account_scope);
- acct_total = report.get_total_expr(args);
+ acct_total = report.fn_total_expr(args);
computed = true;
}
diff --git a/src/output.h b/src/output.h
index af8e9e82..d3dd6560 100644
--- a/src/output.h
+++ b/src/output.h
@@ -47,7 +47,6 @@
#define _OUTPUT_H
#include "report.h"
-#include "handler.h"
#include "format.h"
namespace ledger {
diff --git a/src/report.cc b/src/report.cc
index 20c9e8e5..95add7a3 100644
--- a/src/report.cc
+++ b/src/report.cc
@@ -66,12 +66,12 @@ void report_t::accounts_report(acct_handler_ptr handler)
{
sum_all_accounts();
- if (sort_string.empty()) {
+ if (! HANDLED(sort_)) {
basic_accounts_iterator walker(*session.master);
pass_down_accounts(handler, walker,
item_predicate<account_t>("total", what_to_keep));
} else {
- sorted_accounts_iterator walker(*session.master, sort_string);
+ sorted_accounts_iterator walker(*session.master, HANDLER(sort_).str());
pass_down_accounts(handler, walker,
item_predicate<account_t>("total", what_to_keep));
}
@@ -84,43 +84,43 @@ void report_t::commodities_report(const string& format)
{
}
-value_t report_t::get_amount_expr(call_scope_t& scope)
+value_t report_t::fn_amount_expr(call_scope_t& scope)
{
return amount_expr.calc(scope);
}
-value_t report_t::get_total_expr(call_scope_t& scope)
+value_t report_t::fn_total_expr(call_scope_t& scope)
{
return total_expr.calc(scope);
}
-value_t report_t::get_display_total(call_scope_t& scope)
+value_t report_t::fn_display_total(call_scope_t& scope)
{
return display_total.calc(scope);
}
-value_t report_t::f_market_value(call_scope_t& args)
-{
- var_t<datetime_t> date(args, 1);
- var_t<string> in_terms_of(args, 2);
+namespace {
+ value_t fn_market_value(call_scope_t& args)
+ {
+ var_t<datetime_t> date(args, 1);
+ var_t<string> in_terms_of(args, 2);
- commodity_t * commodity = NULL;
- if (in_terms_of)
- commodity = amount_t::current_pool->find_or_create(*in_terms_of);
+ commodity_t * commodity = NULL;
+ if (in_terms_of)
+ commodity = amount_t::current_pool->find_or_create(*in_terms_of);
- DEBUG("report.market", "getting market value of: " << args[0]);
+ DEBUG("report.market", "getting market value of: " << args[0]);
- value_t result =
- args[0].value(date ? optional<datetime_t>(*date) : optional<datetime_t>(),
- commodity ? optional<commodity_t&>(*commodity) :
- optional<commodity_t&>());
+ value_t result =
+ args[0].value(date ? optional<datetime_t>(*date) : optional<datetime_t>(),
+ commodity ? optional<commodity_t&>(*commodity) :
+ optional<commodity_t&>());
- DEBUG("report.market", "result is: " << result);
- return result;
-}
+ DEBUG("report.market", "result is: " << result);
+ return result;
+ }
-namespace {
- value_t print_balance(call_scope_t& args)
+ value_t fn_print_balance(call_scope_t& args)
{
report_t& report(find_scope<report_t>(args));
@@ -136,13 +136,13 @@ namespace {
return string_value(out.str());
}
- value_t strip_annotations(call_scope_t& args)
+ value_t fn_strip(call_scope_t& args)
{
report_t& report(find_scope<report_t>(args));
return args[0].strip_annotations(report.what_to_keep);
}
- value_t truncate(call_scope_t& args)
+ value_t fn_truncate(call_scope_t& args)
{
report_t& report(find_scope<report_t>(args));
@@ -153,16 +153,24 @@ namespace {
account_abbrev ? *account_abbrev : -1));
}
- value_t display_date(call_scope_t& args)
+ value_t fn_display_date(call_scope_t& args)
{
report_t& report(find_scope<report_t>(args));
item_t& item(find_scope<item_t>(args));
- if (item.use_effective_date) {
+ date_t when;
+ if (report.HANDLED(effective)) {
if (optional<date_t> date = item.effective_date())
- return string_value(format_date(*date, report.output_date_format));
+ when = *date;
+ } else {
+ when = item.date();
}
- return string_value(format_date(item.date(), report.output_date_format));
+
+ if (report.HANDLED(output_date_format_))
+ return string_value
+ (format_date(when, report.HANDLER(output_date_format_).str()));
+ else
+ return string_value(format_date(when));
}
template <class Type = xact_t,
@@ -195,41 +203,29 @@ namespace {
};
}
+#if 0
+// Commands yet to implement:
+//
+// entry
+// prices
+// pricesdb
+// csv
+// emacs | lisp
+#endif
+
+#define FORMAT(member) \
+ (HANDLED(format_) ? HANDLER(format_).str() : session.member)
+
expr_t::ptr_op_t report_t::lookup(const string& name)
{
const char * p = name.c_str();
switch (*p) {
case 'a':
- if (std::strcmp(p, "amount_expr") == 0)
- return MAKE_FUNCTOR(report_t::get_amount_expr);
- break;
-
- case 'd':
- if (std::strcmp(p, "display_total") == 0)
- return MAKE_FUNCTOR(report_t::get_display_total);
- else if (std::strcmp(p, "display_date") == 0)
- return WRAP_FUNCTOR(display_date);
+ METHOD(report_t, amount_expr);
break;
- case 'l':
- if (std::strncmp(p, "ledger_cmd_", 11) == 0) {
-
-#define FORMAT(str) (format_string.empty() ? session. str : format_string)
-
-#if 0
- // Commands yet to implement:
- //
- // entry
- // dump
- // output
- // prices
- // pricesdb
- // csv
- // emacs | lisp
- // xml
-#endif
-
- p = p + 11;
+ case 'c':
+ if (WANT_CMD()) { p += CMD_PREFIX_LEN;
switch (*p) {
case 'b':
if (*(p + 1) == '\0' ||
@@ -262,297 +258,212 @@ expr_t::ptr_op_t report_t::lookup(const string& name)
break;
}
}
- else if (std::strncmp(p, "ledger_precmd_", 14) == 0) {
- p = p + 14;
- switch (*p) {
- case 'a':
- if (std::strcmp(p, "args") == 0)
- return WRAP_FUNCTOR(args_command);
- break;
-
- case 'p':
- if (std::strcmp(p, "parse") == 0)
- return WRAP_FUNCTOR(parse_command);
- else if (std::strcmp(p, "period") == 0)
- return WRAP_FUNCTOR(period_command);
- break;
-
- case 'e':
- if (std::strcmp(p, "eval") == 0)
- return WRAP_FUNCTOR(eval_command);
- break;
+ break;
- case 'f':
- if (std::strcmp(p, "format") == 0)
- return WRAP_FUNCTOR(format_command);
- break;
- }
- }
+ case 'd':
+ METHOD(report_t, display_total);
+ else FUNCTION(display_date);
break;
case 'm':
- if (std::strcmp(p, "market_value") == 0)
- return MAKE_FUNCTOR(report_t::f_market_value);
+ FUNCTION(market_value);
break;
case 'o':
- if (std::strncmp(p, "opt_", 4) == 0) {
- p = p + 4;
+ if (WANT_OPT()) { p += OPT_PREFIX_LEN;
switch (*p) {
case 'a':
- if (std::strcmp(p, "amount_") == 0)
- return MAKE_FUNCTOR(report_t::option_amount_);
- else if (std::strcmp(p, "ansi") == 0)
- return MAKE_FUNCTOR(report_t::option_ansi);
- else if (std::strcmp(p, "ansi-invert") == 0)
- return MAKE_FUNCTOR(report_t::option_ansi_invert);
- else if (std::strcmp(p, "anon") == 0)
- return MAKE_FUNCTOR(report_t::option_anon);
+ OPT(amount_);
+ else OPT(anon);
break;
case 'b':
- if (std::strcmp(p, "b_") == 0 ||
- std::strcmp(p, "begin_") == 0)
- return MAKE_FUNCTOR(report_t::option_begin_);
- else if (std::strcmp(p, "base") == 0)
- return MAKE_FUNCTOR(report_t::option_base);
- else if (std::strcmp(p, "by-payee") == 0)
- return MAKE_FUNCTOR(report_t::option_by_payee);
+ OPT_(begin_);
+ else OPT(base);
+ else OPT(by_payee);
break;
case 'c':
- if (! *(p + 1) || std::strcmp(p, "current") == 0)
- return MAKE_FUNCTOR(report_t::option_current);
- else if (std::strcmp(p, "collapse") == 0)
- return MAKE_FUNCTOR(report_t::option_collapse);
- else if (std::strcmp(p, "cleared") == 0)
- return MAKE_FUNCTOR(report_t::option_cleared);
- else if (std::strcmp(p, "cost") == 0)
- return MAKE_FUNCTOR(report_t::option_cost);
- else if (std::strcmp(p, "comm-as-payee") == 0)
- return MAKE_FUNCTOR(report_t::option_comm_as_payee);
- else if (std::strcmp(p, "code-as-payee") == 0)
- return MAKE_FUNCTOR(report_t::option_code_as_payee);
+ OPT_(current);
+ else OPT(collapse);
+ else OPT(cleared);
+ else OPT(cost);
+ else OPT(comm_as_payee);
+ else OPT(code_as_payee);
break;
case 'd':
- if (std::strcmp(p, "daily") == 0)
- return MAKE_FUNCTOR(report_t::option_daily);
- else if (std::strcmp(p, "dow") == 0)
- return MAKE_FUNCTOR(report_t::option_dow);
- else if (std::strcmp(p, "date-format_") == 0)
- return MAKE_FUNCTOR(report_t::option_date_format_);
+ OPT(daily);
+ else OPT(dow);
+ else OPT(date_format_);
break;
case 'e':
- if (std::strcmp(p, "e_") == 0 ||
- std::strcmp(p, "end_") == 0)
- return MAKE_FUNCTOR(report_t::option_end_);
- else if (std::strcmp(p, "empty") == 0)
- return MAKE_FUNCTOR(report_t::option_empty);
+ OPT_(end_);
+ else OPT(empty);
+ else OPT(effective);
break;
case 'f':
- if (std::strcmp(p, "format_") == 0)
- return MAKE_FUNCTOR(report_t::option_format_);
+ OPT(format_);
break;
case 'h':
- if (std::strcmp(p, "head_") == 0)
- return MAKE_FUNCTOR(report_t::option_head_);
+ OPT(head_);
break;
case 'i':
- if (std::strcmp(p, "input-date-format_") == 0)
- return MAKE_FUNCTOR(report_t::option_input_date_format_);
+ OPT(input_date_format_);
+ else OPT(invert);
break;
case 'j':
- if (! *(p + 1))
- return MAKE_FUNCTOR(report_t::option_amount_data);
+ OPT_CH(amount_data);
break;
case 'l':
- if (std::strcmp(p, "l_") == 0
- || std::strcmp(p, "limit_") == 0)
- return MAKE_FUNCTOR(report_t::option_limit_);
+ OPT_(limit);
break;
case 'm':
- if (std::strcmp(p, "monthly") == 0)
- return MAKE_FUNCTOR(report_t::option_monthly);
- else if (std::strcmp(p, "market") == 0)
- return MAKE_FUNCTOR(report_t::option_market);
+ OPT(monthly);
+ else OPT(market);
break;
case 'n':
- if (std::strcmp(p, "n") == 0)
- return MAKE_FUNCTOR(report_t::option_collapse);
+ OPT_CH(collapse);
+ break;
+
+ case 'o':
+ OPT_(output_);
+ else OPT(output_date_format_);
break;
case 'p':
- if (std::strcmp(p, "p_") == 0 ||
- std::strcmp(p, "period_") == 0)
- return MAKE_FUNCTOR(report_t::option_period_);
- else if (std::strcmp(p, "period_sort_") == 0)
- return MAKE_FUNCTOR(report_t::option_period_sort_);
- else if (std::strcmp(p, "price") == 0)
- return MAKE_FUNCTOR(report_t::option_price);
- else if (std::strcmp(p, "price_db_") == 0)
- return MAKE_FUNCTOR(report_t::option_price_db_);
+ OPT_(period_);
+ else OPT(period_sort_);
+ else OPT(price);
+ else OPT(price_db_);
break;
case 'q':
- if (std::strcmp(p, "quarterly") == 0)
- return MAKE_FUNCTOR(report_t::option_quarterly);
- else if (std::strcmp(p, "quantity") == 0)
- return MAKE_FUNCTOR(report_t::option_quantity);
+ OPT(quarterly);
+ else OPT(quantity);
break;
case 'r':
- if (std::strcmp(p, "r") == 0 ||
- std::strcmp(p, "related") == 0)
- return MAKE_FUNCTOR(report_t::option_related);
+ OPT_(related);
+ else OPT_(related_all);
break;
case 's':
- if (std::strcmp(p, "s") == 0 ||
- std::strcmp(p, "subtotal") == 0)
- return MAKE_FUNCTOR(report_t::option_subtotal);
- else if (std::strcmp(p, "sort_") == 0)
- return MAKE_FUNCTOR(report_t::option_sort_);
- else if (std::strcmp(p, "sort_entries_") == 0)
- return MAKE_FUNCTOR(report_t::option_sort_entries_);
- else if (std::strcmp(p, "sort_all_") == 0)
- return MAKE_FUNCTOR(report_t::option_sort_all_);
+ OPT_(subtotal);
+ else OPT(sort_);
+ else OPT(sort_all_);
+ else OPT(sort_entries_);
break;
case 't':
- if (std::strcmp(p, "t_") == 0)
- return MAKE_FUNCTOR(report_t::option_amount_);
- else if (std::strcmp(p, "total_") == 0)
- return MAKE_FUNCTOR(report_t::option_total_);
- else if (std::strcmp(p, "totals") == 0)
- return MAKE_FUNCTOR(report_t::option_totals);
- else if (std::strcmp(p, "tail_") == 0)
- return MAKE_FUNCTOR(report_t::option_tail_);
+ OPT_CH(amount_);
+ else OPT(total_);
+ else OPT(totals);
+ else OPT(tail_);
break;
case 'u':
- if (std::strcmp(p, "uncleared") == 0)
- return MAKE_FUNCTOR(report_t::option_uncleared);
+ OPT(uncleared);
break;
case 'w':
- if (std::strcmp(p, "weekly") == 0)
- return MAKE_FUNCTOR(report_t::option_weekly);
+ OPT(weekly);
break;
case 'x':
- if (std::strcmp(p, "x"))
- return MAKE_FUNCTOR(report_t::option_comm_as_payee);
+ OPT_CH(comm_as_payee); // jww (2009-02-05): ???
break;
case 'y':
- if (std::strcmp(p, "yearly") == 0)
- return MAKE_FUNCTOR(report_t::option_yearly);
- else if (std::strcmp(p, "y_") == 0)
- return MAKE_FUNCTOR(report_t::option_date_format_);
+ OPT_CH(date_format_);
+ else OPT(yearly);
break;
case 'B':
- if (! *(p + 1))
- return MAKE_FUNCTOR(report_t::option_cost);
+ OPT_CH(cost);
break;
-
case 'C':
- if (! *(p + 1))
- return MAKE_FUNCTOR(report_t::option_cleared);
+ OPT_CH(cleared);
break;
-
case 'E':
- if (! *(p + 1))
- return MAKE_FUNCTOR(report_t::option_empty);
+ OPT_CH(empty);
break;
-
case 'F':
- if (std::strcmp(p, "F_") == 0)
- return MAKE_FUNCTOR(report_t::option_format_);
+ OPT_CH(format_);
break;
-
case 'I':
- if (! *(p + 1))
- return MAKE_FUNCTOR(report_t::option_price);
+ OPT_CH(price);
break;
-
case 'J':
- if (! *(p + 1))
- return MAKE_FUNCTOR(report_t::option_total_data);
+ OPT_CH(total_data);
break;
-
case 'M':
- if (! *(p + 1))
- return MAKE_FUNCTOR(report_t::option_monthly);
+ OPT_CH(monthly);
break;
-
case 'O':
- if (! *(p + 1))
- return MAKE_FUNCTOR(report_t::option_quantity);
+ OPT_CH(quantity);
break;
-
case 'P':
- if (! *(p + 1))
- return MAKE_FUNCTOR(report_t::option_by_payee);
+ OPT_CH(by_payee);
break;
-
case 'S':
- if (std::strcmp(p, "S_") == 0)
- return MAKE_FUNCTOR(report_t::option_sort_);
+ OPT_CH(sort_);
break;
-
case 'T':
- if (std::strcmp(p, "T_") == 0)
- return MAKE_FUNCTOR(report_t::option_total_);
+ OPT_CH(total_);
break;
-
case 'U':
- if (! *(p + 1))
- return MAKE_FUNCTOR(report_t::option_uncleared);
+ OPT_CH(uncleared);
break;
-
case 'V':
- if (! *(p + 1))
- return MAKE_FUNCTOR(report_t::option_market);
+ OPT_CH(market);
break;
-
case 'W':
- if (! *(p + 1))
- return MAKE_FUNCTOR(report_t::option_weekly);
+ OPT_CH(weekly);
break;
-
case 'Y':
- if (! *(p + 1))
- return MAKE_FUNCTOR(report_t::option_yearly);
+ OPT_CH(yearly);
break;
}
}
break;
case 'p':
- if (std::strcmp(p, "print_balance") == 0)
- return WRAP_FUNCTOR(print_balance);
+ if (WANT_PRECMD()) { p += PRECMD_PREFIX_LEN;
+ switch (*p) {
+ case 'a':
+ COMMAND(args);
+ break;
+ case 'p':
+ COMMAND(parse);
+ else COMMAND(period);
+ break;
+ case 'e':
+ COMMAND(eval);
+ break;
+ case 'f':
+ COMMAND(format);
+ break;
+ }
+ }
+ else FUNCTION(print_balance);
break;
case 's':
- if (std::strcmp(p, "strip") == 0)
- return WRAP_FUNCTOR(strip_annotations);
+ FUNCTION(strip);
break;
case 't':
- if (std::strcmp(p, "total_expr") == 0)
- return MAKE_FUNCTOR(report_t::get_total_expr);
- else if (std::strcmp(p, "truncate") == 0)
- return WRAP_FUNCTOR(truncate);
+ FUNCTION(truncate);
+ else METHOD(report_t, total_expr);
break;
}
diff --git a/src/report.h b/src/report.h
index 541122a9..62664ba1 100644
--- a/src/report.h
+++ b/src/report.h
@@ -47,7 +47,7 @@
#define _REPORT_H
#include "session.h"
-#include "handler.h"
+#include "chain.h"
namespace ledger {
@@ -105,144 +105,112 @@ class report_t : public scope_t
report_t();
public:
- optional<path> output_file;
+ session_t& session;
+ string account;
output_stream_t output_stream;
+ keep_details_t what_to_keep;
- string format_string;
- string output_date_format;
- string predicate;
- string secondary_predicate;
- string display_predicate;
- string report_period;
- string report_period_sort;
- string sort_string;
- string descend_expr;
- string forecast_limit;
- string reconcile_balance;
- string reconcile_date;
+ uint_least8_t budget_flags;
expr_t amount_expr;
expr_t total_expr;
expr_t display_total;
- uint_least8_t budget_flags;
+ string predicate;
+ string secondary_predicate;
+ string display_predicate;
+ string report_period;
+ string report_period_sort;
- long head_entries;
- long tail_entries;
-
- bool show_collapsed;
- bool show_subtotal;
- bool show_totals;
- bool show_related;
- bool show_all_related;
- bool show_inverted;
- bool show_empty;
- bool days_of_the_week;
- bool by_payee;
- bool comm_as_payee;
- bool code_as_payee;
bool show_revalued;
bool show_revalued_only;
- bool entry_sort;
- bool sort_all;
- bool anonymize;
- bool use_effective_date;
-
- keep_details_t what_to_keep;
-
- string account;
-
- bool raw_mode;
-
- session_t& session;
explicit report_t(session_t& _session)
- : output_date_format("%y-%b-%d"),
+ : session(_session),
amount_expr("amount"),
total_expr("total"),
display_total("total_expr"),
- head_entries(0),
- tail_entries(0),
-
- show_collapsed(false),
- show_subtotal(false),
- show_totals(false),
- show_related(false),
- show_all_related(false),
- show_inverted(false),
- show_empty(false),
- days_of_the_week(false),
- by_payee(false),
- comm_as_payee(false),
- code_as_payee(false),
show_revalued(false),
- show_revalued_only(false),
- entry_sort(false),
- sort_all(false),
- anonymize(false),
- use_effective_date(false),
-
- raw_mode(false),
-
- session(_session)
+ show_revalued_only(false)
{
TRACE_CTOR(report_t, "session_t&");
+
+ // Setup default values for some of the option handlers
+ HANDLER(output_date_format_).value = "%y-%b-%d";
}
report_t(const report_t& other)
: scope_t(),
- output_file(other.output_file),
+ session(other.session),
+ account(other.account),
+ what_to_keep(other.what_to_keep),
- format_string(other.format_string),
- output_date_format(other.output_date_format),
- predicate(other.predicate),
- secondary_predicate(other.secondary_predicate),
- display_predicate(other.display_predicate),
- report_period(other.report_period),
- report_period_sort(other.report_period_sort),
- sort_string(other.sort_string),
- descend_expr(other.descend_expr),
- forecast_limit(other.forecast_limit),
- reconcile_balance(other.reconcile_balance),
- reconcile_date(other.reconcile_date),
+ budget_flags(other.budget_flags),
amount_expr(other.amount_expr),
total_expr(other.total_expr),
display_total(other.display_total),
- budget_flags(other.budget_flags),
+ predicate(other.predicate),
+ secondary_predicate(other.secondary_predicate),
+ display_predicate(other.display_predicate),
+ report_period(other.report_period),
+ report_period_sort(other.report_period_sort),
- head_entries(other.head_entries),
- tail_entries(other.tail_entries),
-
- show_collapsed(other.show_collapsed),
- show_subtotal(other.show_subtotal),
- show_totals(other.show_totals),
- show_related(other.show_related),
- show_all_related(other.show_all_related),
- show_inverted(other.show_inverted),
- show_empty(other.show_empty),
- days_of_the_week(other.days_of_the_week),
- by_payee(other.by_payee),
- comm_as_payee(other.comm_as_payee),
- code_as_payee(other.code_as_payee),
show_revalued(other.show_revalued),
show_revalued_only(other.show_revalued_only),
- entry_sort(other.entry_sort),
- sort_all(other.sort_all),
- anonymize(other.anonymize),
- use_effective_date(other.use_effective_date),
-
- what_to_keep(other.what_to_keep),
- account(other.account),
-
- raw_mode(other.raw_mode),
-
- session(other.session)
+ COPY_OPT(amount_, other),
+ COPY_OPT(amount_data, other),
+ COPY_OPT(anon, other),
+ COPY_OPT(base, other),
+ COPY_OPT(by_payee, other),
+ COPY_OPT(cleared, other),
+ COPY_OPT(code_as_payee, other),
+ COPY_OPT(collapse, other),
+ COPY_OPT(comm_as_payee, other),
+ COPY_OPT(cost, other),
+ COPY_OPT(current, other),
+ COPY_OPT(daily, other),
+ COPY_OPT(date_format_, other),
+ COPY_OPT(dow, other),
+ COPY_OPT(effective, other),
+ COPY_OPT(empty, other),
+ COPY_OPT(format_, other),
+ COPY_OPT(head_, other),
+ COPY_OPT(input_date_format_, other),
+ COPY_OPT(invert, other),
+ COPY_OPT(limit, other),
+ COPY_OPT(market, other),
+ COPY_OPT(monthly, other),
+ COPY_OPT(output_, other),
+ COPY_OPT(output_date_format_, other),
+ COPY_OPT(period_, other),
+ COPY_OPT(period_sort_, other),
+ COPY_OPT(price, other),
+ COPY_OPT(price_db_, other),
+ COPY_OPT(quantity, other),
+ COPY_OPT(quarterly, other),
+ COPY_OPT(related, other),
+ COPY_OPT(related_all, other),
+ COPY_OPT(subtotal, other),
+ COPY_OPT(tail_, other),
+ COPY_OPT(total_, other),
+ COPY_OPT(total_data, other),
+ COPY_OPT(totals, other),
+ COPY_OPT(uncleared, other),
+ COPY_OPT(weekly, other),
+ COPY_OPT(yearly, other),
+
+ COPY_OPT(begin_, other),
+ COPY_OPT(end_, other),
+
+ COPY_OPT(sort_, other),
+ COPY_OPT(sort_all_, other),
+ COPY_OPT(sort_entries_, other)
{
TRACE_CTOR(report_t, "copy");
}
@@ -262,6 +230,110 @@ public:
void accounts_report(acct_handler_ptr handler);
void commodities_report(const string& format);
+ value_t fn_amount_expr(call_scope_t& scope);
+ value_t fn_total_expr(call_scope_t& scope);
+ value_t fn_display_total(call_scope_t& scope);
+
+ void append_predicate(const string& str) {
+ if (! predicate.empty())
+ predicate = string("(") + predicate + ")&";
+ predicate += str;
+ }
+
+ /**
+ * Option handlers
+ */
+
+ OPTION(report_t, amount_);
+ OPTION(report_t, amount_data);
+ OPTION(report_t, anon);
+ OPTION(report_t, base);
+ OPTION(report_t, by_payee);
+ OPTION(report_t, cleared);
+ OPTION(report_t, code_as_payee);
+ OPTION(report_t, collapse);
+ OPTION(report_t, comm_as_payee);
+ OPTION(report_t, cost);
+ OPTION(report_t, current);
+ OPTION(report_t, daily);
+ OPTION(report_t, date_format_);
+ OPTION(report_t, dow);
+ OPTION(report_t, effective);
+ OPTION(report_t, empty);
+ OPTION(report_t, format_);
+ OPTION(report_t, head_);
+ OPTION(report_t, input_date_format_);
+ OPTION(report_t, invert);
+ OPTION(report_t, limit);
+ OPTION(report_t, market);
+ OPTION(report_t, monthly);
+ OPTION(report_t, output_);
+ OPTION(report_t, output_date_format_);
+ OPTION(report_t, period_);
+ OPTION(report_t, period_sort_);
+ OPTION(report_t, price);
+ OPTION(report_t, price_db_);
+ OPTION(report_t, quantity);
+ OPTION(report_t, quarterly);
+ OPTION(report_t, related);
+ OPTION(report_t, related_all);
+ OPTION(report_t, subtotal);
+ OPTION(report_t, tail_);
+ OPTION(report_t, total_);
+ OPTION(report_t, total_data);
+ OPTION(report_t, totals);
+ OPTION(report_t, uncleared);
+ OPTION(report_t, weekly);
+ OPTION(report_t, yearly);
+
+ OPTION_(report_t, begin_, DO_(args) {
+ interval_t interval(args[0].to_string());
+ if (! is_valid(interval.begin))
+ throw_(std::invalid_argument,
+ "Could not determine beginning of period '"
+ << args[0].to_string() << "'");
+
+ if (! parent->predicate.empty())
+ parent->predicate += "&";
+ parent->predicate += "date>=[";
+ parent->predicate += to_iso_extended_string(interval.begin);
+ parent->predicate += "]";
+ });
+
+ OPTION_(report_t, end_, DO_(args) {
+ interval_t interval(args[0].to_string());
+ if (! is_valid(interval.begin))
+ throw_(std::invalid_argument,
+ "Could not determine end of period '"
+ << args[0].to_string() << "'");
+
+ if (! parent->predicate.empty())
+ parent->predicate += "&";
+ parent->predicate += "date<[";
+ parent->predicate += to_iso_extended_string(interval.begin);
+ parent->predicate += "]";
+
+#if 0
+ terminus = interval.begin;
+#endif
+ });
+
+ OPTION_(report_t, sort_, DO_(args) {
+ on(args[0].to_string());
+ parent->HANDLER(sort_entries_).off();
+ parent->HANDLER(sort_all_).off();
+ });
+
+ OPTION_(report_t, sort_all_, DO_(args) {
+ parent->HANDLER(sort_).on(args[0].to_string());
+ parent->HANDLER(sort_entries_).off();
+ });
+
+ OPTION_(report_t, sort_entries_, DO_(args) {
+ parent->HANDLER(sort_).on(args[0].to_string());
+ parent->HANDLER(sort_all_).off();
+ });
+
#if 0
//////////////////////////////////////////////////////////////////////
//
@@ -292,11 +364,6 @@ public:
throw int(0);
}
- value_t option_version(call_scope_t& args) { // v
- show_version(std::cout);
- throw int(0);
- }
-
value_t option_init_file(call_scope_t& args) { // i:
std::string path = resolve_path(optarg);
if (access(path.c_str(), R_OK) != -1)
@@ -306,66 +373,14 @@ public:
"The init file '" << path << "' does not exist or is not readable");
}
- value_t option_output(call_scope_t& args) { // o:
- if (std::string(optarg) != "-") {
- std::string path = resolve_path(optarg);
- report->output_file = path;
- }
- }
-
value_t option_account(call_scope_t& args) { // a:
config->account = optarg;
}
-#endif
//////////////////////////////////////////////////////////////////////
//
// Report filtering
- value_t ignore(call_scope_t&) {
- return true;
- }
-
- value_t option_effective(call_scope_t&) {
- use_effective_date = true;
- return true;
- }
-
- value_t option_begin_(call_scope_t& args) { // b:
- interval_t interval(args[0].to_string());
- if (! is_valid(interval.begin))
- throw_(std::invalid_argument,
- "Could not determine beginning of period '"
- << args[0].to_string() << "'");
-
- if (! predicate.empty())
- predicate += "&";
- predicate += "date>=[";
- predicate += to_iso_extended_string(interval.begin);
- predicate += "]";
-
- return true;
- }
-
- value_t option_end_(call_scope_t& args) { // e:
- interval_t interval(args[0].to_string());
- if (! is_valid(interval.begin))
- throw_(std::invalid_argument,
- "Could not determine end of period '"
- << args[0].to_string() << "'");
-
- if (! predicate.empty())
- predicate += "&";
- predicate += "date<[";
- predicate += to_iso_extended_string(interval.begin);
- predicate += "]";
-
-#if 0
- terminus = interval.begin;
-#endif
- return true;
- }
-
value_t option_current(call_scope_t& args) { // c
if (! predicate.empty())
predicate += "&";
@@ -403,7 +418,7 @@ public:
value_t option_lots(call_scope_t& args) {
what_to_keep.keep_price = true;
what_to_keep.keep_date = true;
- what_to_keep.keep_tag = true;
+ what_to_keep.keep_tag = true;
}
value_t option_lot_prices(call_scope_t& args) {
@@ -423,21 +438,6 @@ public:
//
// Output customization
- value_t option_format_(call_scope_t& args) { // F:
- format_string = args[0].as_string();
- return true;
- }
-
- value_t option_date_format_(call_scope_t& args) { // y:
- output_date_format = args[0].as_string();
- return true;
- }
-
- value_t option_input_date_format_(call_scope_t& args) { // :
- ledger::input_date_format = args[0].as_string();
- return true;
- }
-
#if 0
value_t option_balance_format(call_scope_t& args) { // :
config->balance_format = optarg;
@@ -702,12 +702,6 @@ public:
}
#endif
- void append_predicate(const string& str) {
- if (! predicate.empty())
- predicate = string("(") + predicate + ")&";
- predicate += str;
- }
-
value_t option_limit_(call_scope_t& args) { // l:
append_predicate(args[0].as_string());
return true;
@@ -732,21 +726,15 @@ public:
#endif
value_t option_amount_(call_scope_t& args) { // t:
- amount_expr = args[0].as_string();
+ _amount_expr = args[0].as_string();
return true;
}
value_t option_total_(call_scope_t& args) { // T:
- total_expr = args[0].as_string();
+ _total_expr = args[0].as_string();
return true;
}
- value_t get_amount_expr(call_scope_t& scope);
- value_t get_total_expr(call_scope_t& scope);
- value_t get_display_total(call_scope_t& scope);
-
- value_t f_market_value(call_scope_t& args);
-
value_t option_amount_data(call_scope_t&) { // j
format_string = session.plot_amount_format;
return true;
@@ -757,22 +745,6 @@ public:
return true;
}
- value_t option_ansi(call_scope_t& args) {
-#if 0
- format_t::ansi_codes = true;
- format_t::ansi_invert = false;
-#endif
- return true;
- }
-
- value_t option_ansi_invert(call_scope_t& args) {
-#if 0
- format_t::ansi_codes =
- format_t::ansi_invert = true;
-#endif
- return true;
- }
-
//////////////////////////////////////////////////////////////////////
//
// Commodity reporting
@@ -801,28 +773,28 @@ public:
value_t option_quantity(call_scope_t& args) { // O
show_revalued = false;
- amount_expr = "amount";
- total_expr = "total";
+ _amount_expr = "amount";
+ _total_expr = "total";
return true;
}
value_t option_cost(call_scope_t& args) { // B
show_revalued = false;
- amount_expr = "cost";
- total_expr = "total_cost";
+ _amount_expr = "cost";
+ _total_expr = "total_cost";
return true;
}
value_t option_price(call_scope_t& args) { // I
show_revalued = false;
- amount_expr = "price";
- total_expr = "price_total";
+ _amount_expr = "price";
+ _total_expr = "price_total";
return true;
}
value_t option_market(call_scope_t& args) { // V
- show_revalued = true;
- display_total = "market_value(total_expr)";
+ show_revalued = true;
+ _display_total = "market_value(total_expr)";
return true;
}
@@ -854,6 +826,7 @@ public:
anonymize = true;
return true;
}
+#endif // 0
//
// Scope members
diff --git a/src/session.cc b/src/session.cc
index ce668bd9..38f15dc9 100644
--- a/src/session.cc
+++ b/src/session.cc
@@ -31,7 +31,6 @@
#include "session.h"
#include "report.h"
-#include "handler.h"
#include "iterators.h"
#include "filters.h"
#include "textual.h"
diff --git a/src/session.h b/src/session.h
index 83a31b96..adf2f4b7 100644
--- a/src/session.h
+++ b/src/session.h
@@ -47,6 +47,7 @@
#define _SESSION_H
#include "scope.h"
+#include "handler.h"
#include "journal.h"
#include "account.h"
#include "format.h"
diff --git a/src/stream.cc b/src/stream.cc
index 535a25a5..94282d2d 100644
--- a/src/stream.cc
+++ b/src/stream.cc
@@ -112,7 +112,7 @@ namespace {
void output_stream_t::initialize(const optional<path>& output_file,
const optional<path>& pager_path)
{
- if (output_file)
+ if (output_file && *output_file != "-")
os = new ofstream(*output_file);
else if (pager_path)
pipe_to_pager_fd = do_fork(&os, *pager_path);
diff --git a/src/textual.cc b/src/textual.cc
index e22d1d28..d6fd966b 100644
--- a/src/textual.cc
+++ b/src/textual.cc
@@ -690,9 +690,9 @@ void textual_parser_t::instance_t::general_directive(char * line)
break;
}
- static const std::size_t textdir_len = std::strlen("ledger_textdir_");
+ static const std::size_t textdir_len = std::strlen("dir_");
scoped_array<char> directive(new char[std::strlen(p) + textdir_len + 1]);
- std::strcpy(directive.get(), "ledger_textdir_");
+ std::strcpy(directive.get(), "dir_");
std::strcpy(directive.get() + textdir_len, p);
if (expr_t::ptr_op_t op = lookup(directive.get())) {
diff --git a/src/textual.h b/src/textual.h
index b6f67157..3565579a 100644
--- a/src/textual.h
+++ b/src/textual.h
@@ -47,7 +47,7 @@
#define _TEXTUAL_H
#include "journal.h"
-#include "handler.h"
+#include "account.h"
namespace ledger {
@@ -166,12 +166,6 @@ protected:
friend class instance_t;
};
-void write_textual_journal(journal_t& journal,
- const path& pathname,
- xact_handler_ptr& formatter,
- const string& write_hdr_format,
- std::ostream& out);
-
} // namespace ledger
#endif // _TEXTUAL_H