Greatly simplified the way option and command handlers are defined.

This commit is contained in:
John Wiegley 2009-02-05 21:18:37 -04:00
parent 7b24e8f8e3
commit 408b819c6e
20 changed files with 730 additions and 649 deletions

View file

@ -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)));
(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));
// 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));
// 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.anonymize)
// 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;

View file

@ -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,

View file

@ -46,8 +46,7 @@
#ifndef _CSV_H
#define _CSV_H
#include "handler.h"
#include "format.h"
#include "output.h"
namespace ledger {

View file

@ -46,8 +46,7 @@
#ifndef _EMACS_H
#define _EMACS_H
#include "handler.h"
#include "format.h"
#include "output.h"
namespace ledger {

View file

@ -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 {

View file

@ -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;
case 'o':
if (WANT_OPT()) { p += OPT_PREFIX_LEN;
switch (*p) {
case 'd':
OPT(debug_);
break;
case 's':
OPT(script_);
break;
case 't':
OPT(trace_);
break;
case 'v':
OPT_(verbose);
else OPT(verify);
break;
}
}
case 'p':
if (WANT_PRECMD()) { p += PRECMD_PREFIX_LEN;
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);
M_COMMAND(global_scope_t, push);
else M_COMMAND(global_scope_t, pop);
break;
}
}
break;
case 'o':
if (std::strncmp(p, "opt_", 4) == 0) {
p = p + 4;
switch (*p) {
case 'd':
if (std::strcmp(p, "debug_") == 0)
return MAKE_FUNCTOR(global_scope_t::ignore);
break;
case 's':
if (std::strcmp(p, "script_") == 0)
return MAKE_FUNCTOR(global_scope_t::option_script_);
break;
case 't':
if (std::strcmp(p, "trace_") == 0)
return MAKE_FUNCTOR(global_scope_t::ignore);
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);
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

View file

@ -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);
};

View file

@ -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>");
}
virtual ~item_handler() {
TRACE_DTOR(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 void flush() {
if (handler.get())
handler->flush();
virtual ~handler_t() {
TRACE_DTOR(handler_t);
}
virtual void operator()(T& item) {
if (handler.get()) {
check_for_signal();
(*handler.get())(item);
}
string desc() const {
std::ostringstream out;
if (ch)
out << "--" << name << " (-" << ch << ")";
else
out << "--" << name;
return out.str();
}
virtual void help(std::ostream& out) {
out << "No help for " << desc() << "\n";
}
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

View file

@ -33,8 +33,6 @@
namespace ledger {
bool item_t::use_effective_date = false;
bool item_t::has_tag(const string& tag) const
{
if (! metadata)

View file

@ -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)

View file

@ -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);

View file

@ -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;
}

View file

@ -47,7 +47,6 @@
#define _OUTPUT_H
#include "report.h"
#include "handler.h"
#include "format.h"
namespace ledger {

View file

@ -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);
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]);
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;
}
namespace {
value_t print_balance(call_scope_t& args)
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);
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&>());
DEBUG("report.market", "result is: " << result);
return result;
}
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);
METHOD(report_t, 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);
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;
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;
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;
}

View file

@ -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),
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),
account(other.account),
COPY_OPT(begin_, other),
COPY_OPT(end_, other),
raw_mode(other.raw_mode),
session(other.session)
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

View file

@ -31,7 +31,6 @@
#include "session.h"
#include "report.h"
#include "handler.h"
#include "iterators.h"
#include "filters.h"
#include "textual.h"

View file

@ -47,6 +47,7 @@
#define _SESSION_H
#include "scope.h"
#include "handler.h"
#include "journal.h"
#include "account.h"
#include "format.h"

View file

@ -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);

View file

@ -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())) {

View file

@ -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