Restored all the option handlers from 2.6.2, but not the options themselves.

This commit is contained in:
John Wiegley 2009-02-06 03:31:41 -04:00
parent ecc5a1aab5
commit cf6babcf90
13 changed files with 547 additions and 1130 deletions

View file

@ -55,10 +55,10 @@ xact_handler_ptr chain_xact_handlers(report_t& report,
// filter_xacts will only pass through xacts matching the
// `display_predicate'.
if (! report.display_predicate.empty())
if (report.HANDLED(display_))
handler.reset(new filter_xacts
(handler, item_predicate<xact_t>(report.display_predicate,
report.what_to_keep)));
(handler, item_predicate<xact_t>(report.HANDLER(display_).str(),
report.what_to_keep())));
// calc_xacts computes the running total. When this appears will
// determine, for example, whether filtered xacts are included or excluded
@ -86,7 +86,7 @@ xact_handler_ptr chain_xact_handlers(report_t& report,
i++)
handler.reset(new component_xacts
(handler,
item_predicate<xact_t>(*i, report.what_to_keep)));
item_predicate<xact_t>(*i, report.what_to_keep())));
remember_components = true;
}
@ -105,10 +105,10 @@ xact_handler_ptr chain_xact_handlers(report_t& report,
// filter_xacts will only pass through xacts matching the
// `secondary_predicate'.
if (! report.secondary_predicate.empty())
if (report.HANDLED(only_))
handler.reset(new filter_xacts
(handler, item_predicate<xact_t>
(report.secondary_predicate, report.what_to_keep)));
(report.HANDLER(only_).str(), report.what_to_keep())));
// sort_xacts will sort all the xacts it sees, based on the `sort_order'
// value expression.
@ -122,9 +122,10 @@ xact_handler_ptr chain_xact_handlers(report_t& report,
// 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));
if (report.HANDLED(revalued))
handler.reset(new changed_value_xacts(handler,
report.HANDLER(total_).expr,
report.HANDLED(revalued_only)));
// collapse_xacts causes entries with multiple xacts to appear as entries
// with a subtotaled xact for each commodity used.
@ -149,8 +150,8 @@ xact_handler_ptr chain_xact_handlers(report_t& report,
// 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,
if (report.HANDLED(period_)) {
handler.reset(new interval_xacts(handler, report.HANDLER(period_).str(),
remember_components));
handler.reset(new sort_xacts(handler, "d"));
}
@ -173,12 +174,12 @@ xact_handler_ptr chain_xact_handlers(report_t& report,
handler.reset(new anonymize_xacts(handler));
// This filter_xacts will only pass through xacts matching the `predicate'.
if (! report.predicate.empty()) {
if (report.HANDLED(limit_)) {
DEBUG("report.predicate",
"Report predicate expression = " << report.predicate);
"Report predicate expression = " << report.HANDLER(limit_).str());
handler.reset(new filter_xacts
(handler, item_predicate<xact_t>(report.predicate,
report.what_to_keep)));
(handler, item_predicate<xact_t>(report.HANDLER(limit_).str(),
report.what_to_keep())));
}
#if 0

View file

@ -61,8 +61,8 @@ global_scope_t::global_scope_t(char ** envp)
// that such options are beginning, since options like -f cause a complete
// override of files found anywhere else.
session().now_at_command_line(false);
read_environment_settings(report(), envp);
session().read_init();
read_environment_settings(envp);
read_init();
}
global_scope_t::~global_scope_t()
@ -76,12 +76,37 @@ global_scope_t::~global_scope_t()
IF_VERIFY() set_session_context(NULL);
}
void global_scope_t::read_init()
{
if (HANDLED(init_file_)) {
path init_file(HANDLER(init_file_).str());
if (exists(init_file)) {
TRACE_START(init, 1, "Read initialization file");
ifstream init(init_file);
journal_t temp;
if (session().read_journal(temp, init_file) > 0 ||
temp.auto_entries.size() > 0 || temp.period_entries.size() > 0) {
throw_(parse_error,
"Entries found in initialization file '" << init_file << "'");
}
TRACE_FINISH(init, 1);
}
}
}
void global_scope_t::read_journal_files()
{
INFO_START(journal, "Read journal file");
string master_account;
if (report().HANDLED(account_))
master_account = report().HANDLER(account_).str();
std::size_t count = session().read_data(*session().create_journal(),
report().account);
master_account);
if (count == 0)
throw_(parse_error, "Failed to locate any journal entries; "
"did you specify a valid file with -f?");
@ -161,7 +186,7 @@ void global_scope_t::execute_command(strings_list args, bool at_repl)
// jww (2009-02-02): This is a complete hack, and a leftover from long,
// long ago. The question is, how best to remove its necessity...
normalize_report_options(report(), verb);
normalize_report_options(verb);
}
// Create the output stream (it might be a file, the console or a PAGER
@ -211,9 +236,6 @@ 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();
@ -224,6 +246,9 @@ expr_t::ptr_op_t global_scope_t::lookup(const string& name)
case 'd':
OPT(debug_);
break;
case 'i':
OPT(init_file_);
break;
case 's':
OPT(script_);
break;
@ -233,6 +258,7 @@ expr_t::ptr_op_t global_scope_t::lookup(const string& name)
case 'v':
OPT_(verbose);
else OPT(verify);
else OPT(version);
break;
}
}
@ -254,6 +280,118 @@ expr_t::ptr_op_t global_scope_t::lookup(const string& name)
return expr_t::ptr_op_t();
}
void global_scope_t::read_environment_settings(char * envp[])
{
TRACE_START(environment, 1, "Processed environment variables");
process_environment(const_cast<const char **>(envp), "LEDGER_", report());
#if 1
// These are here for backwards compatability, but are deprecated.
if (const char * p = std::getenv("LEDGER"))
process_option("file", report(), p, "LEDGER");
if (const char * p = std::getenv("LEDGER_INIT"))
process_option("init-file", report(), p, "LEDGER_INIT");
if (const char * p = std::getenv("PRICE_HIST"))
process_option("price-db", report(), p, "PRICE_HIST");
if (const char * p = std::getenv("PRICE_EXP"))
process_option("price-exp", report(), p, "PRICE_EXP");
#endif
TRACE_FINISH(environment, 1);
}
strings_list
global_scope_t::read_command_arguments(scope_t& scope, strings_list args)
{
TRACE_START(arguments, 1, "Processed command-line arguments");
strings_list remaining = process_arguments(args, scope);
TRACE_FINISH(arguments, 1);
return remaining;
}
void global_scope_t::normalize_session_options()
{
INFO("Initialization file is " << HANDLER(init_file_).str());
INFO("Price database is " << session().HANDLER(price_db_).str());
foreach (const path& pathname, session().HANDLER(file_).data_files)
INFO("Journal file is " << pathname.string());
}
function_t global_scope_t::look_for_precommand(scope_t& scope,
const string& verb)
{
if (expr_t::ptr_op_t def = scope.lookup(string("precmd_") + verb))
return def->as_function();
else
return function_t();
}
function_t global_scope_t::look_for_command(scope_t& scope,
const string& verb)
{
if (expr_t::ptr_op_t def = scope.lookup(string("cmd_") + verb))
return def->as_function();
else
return function_t();
}
void global_scope_t::normalize_report_options(const string& verb)
{
// Patch up some of the reporting options based on what kind of
// command it was.
report_t& rep(report());
// jww (2008-08-14): This code really needs to be rationalized away
// for 3.0.
if (verb == "print" || verb == "entry" || verb == "dump") {
rep.HANDLER(related).on();
rep.HANDLER(related_all).on();
}
else if (verb == "equity") {
rep.HANDLER(subtotal).on();
}
else if (rep.HANDLED(related)) {
if (verb[0] == 'r') {
rep.HANDLER(invert).on();
} else {
rep.HANDLER(subtotal).on();
rep.HANDLER(related_all).on();
}
}
if (verb[0] != 'b' && verb[0] != 'r')
rep.HANDLER(base).on();
// Setup the default value for the display predicate
if (! rep.HANDLED(display_)) {
if (verb[0] == 'b') {
if (! rep.HANDLED(empty))
rep.append_display_predicate("total");
if (! rep.HANDLED(subtotal))
rep.append_display_predicate("depth<=1");
}
else if (verb == "equity") {
// jww (2008-08-14): ???
rep.append_display_predicate("amount_expr");
}
else if (verb[0] == 'r' && ! rep.HANDLED(empty)) {
rep.append_display_predicate("amount");
}
}
if (rep.HANDLED(period_) && ! rep.HANDLED(sort_all_))
rep.HANDLER(sort_entries_).on();
}
void handle_debug_options(int argc, char * argv[])
{
for (int i = 1; i < argc; i++) {
@ -293,114 +431,4 @@ void handle_debug_options(int argc, char * argv[])
}
}
void read_environment_settings(report_t& report, char * envp[])
{
TRACE_START(environment, 1, "Processed environment variables");
process_environment(const_cast<const char **>(envp), "LEDGER_",
report);
#if 1
// These are here for backwards compatability, but are deprecated.
if (const char * p = std::getenv("LEDGER"))
process_option("file", report, p, "LEDGER");
if (const char * p = std::getenv("LEDGER_INIT"))
process_option("init-file", report, p, "LEDGER_INIT");
if (const char * p = std::getenv("PRICE_HIST"))
process_option("price-db", report, p, "PRICE_HIST");
if (const char * p = std::getenv("PRICE_EXP"))
process_option("price-exp", report, p, "PRICE_EXP");
#endif
TRACE_FINISH(environment, 1);
}
strings_list read_command_arguments(scope_t& scope, strings_list args)
{
TRACE_START(arguments, 1, "Processed command-line arguments");
strings_list remaining = process_arguments(args, scope);
TRACE_FINISH(arguments, 1);
return remaining;
}
void normalize_session_options(session_t& session)
{
INFO("Initialization file is " << session.init_file->string());
INFO("Price database is " << session.price_db->string());
foreach (const path& pathname, session.data_files)
INFO("Journal file is " << pathname.string());
}
function_t look_for_precommand(scope_t& scope, const string& verb)
{
if (expr_t::ptr_op_t def = scope.lookup(string("precmd_") + verb))
return def->as_function();
else
return function_t();
}
function_t look_for_command(scope_t& scope, const string& verb)
{
if (expr_t::ptr_op_t def = scope.lookup(string("cmd_") + verb))
return def->as_function();
else
return function_t();
}
void normalize_report_options(report_t& report, const string& verb)
{
// Patch up some of the reporting options based on what kind of
// command it was.
// jww (2008-08-14): This code really needs to be rationalized away
// for 3.0.
if (verb == "print" || verb == "entry" || verb == "dump") {
report.HANDLER(related).on();
report.HANDLER(related_all).on();
}
else if (verb == "equity") {
report.HANDLER(subtotal).on();
}
else if (report.HANDLED(related)) {
if (verb[0] == 'r') {
report.HANDLER(invert).on();
} else {
report.HANDLER(subtotal).on();
report.HANDLER(related_all).on();
}
}
if (verb[0] != 'b' && verb[0] != 'r')
report.what_to_keep.keep_base = true;
// Setup the default value for the display predicate
if (report.display_predicate.empty()) {
if (verb[0] == 'b') {
if (! report.HANDLED(empty))
report.display_predicate = "total";
if (! report.HANDLED(subtotal)) {
if (! report.display_predicate.empty())
report.display_predicate += "&";
report.display_predicate += "depth<=1";
}
}
else if (verb == "equity") {
report.display_predicate = "amount_expr"; // jww (2008-08-14): ???
}
else if (verb[0] == 'r' && ! report.HANDLED(empty)) {
report.display_predicate = "amount";
}
}
if (! report.report_period.empty() && ! report.HANDLED(sort_all_))
report.HANDLER(sort_entries_).on();
}
} // namespace ledger

View file

@ -51,7 +51,14 @@ public:
global_scope_t(char ** envp);
~global_scope_t();
void read_journal_files();
void read_init();
void read_journal_files();
void read_environment_settings(char * envp[]);
strings_list read_command_arguments(scope_t& scope, strings_list args);
void normalize_session_options();
function_t look_for_precommand(scope_t& scope, const string& verb);
function_t look_for_command(scope_t& scope, const string& verb);
void normalize_report_options(const string& verb);
char * prompt_string();
@ -92,22 +99,41 @@ public:
return true;
}
void show_version_info(std::ostream& out) {
out <<
"Ledger " << ledger::version << ", the command-line accounting tool";
out <<
"\n\nCopyright (c) 2003-2009, John Wiegley. All rights reserved.\n\n\
This program is made available under the terms of the BSD Public License.\n\
See LICENSE file included with the distribution for details and disclaimer.";
out << std::endl;
}
virtual expr_t::ptr_op_t lookup(const string& name);
OPTION(global_scope_t, debug_);
OPTION__
(global_scope_t, init_file_,
CTOR(global_scope_t, init_file_) {
if (const char * home_var = std::getenv("HOME"))
on((path(home_var) / ".ledgerrc").string());
else
on(path("./.ledgerrc").string());
});
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);
OPTION_(global_scope_t, version, DO() {
parent->show_version_info(std::cout);
throw int(0); // exit immediately
});
};
void handle_debug_options(int argc, char * argv[]);
void read_environment_settings(report_t& report, char * envp[]);
strings_list read_command_arguments(scope_t& scope, strings_list args);
void normalize_session_options(session_t& session);
function_t look_for_precommand(scope_t& scope, const string& verb);
function_t look_for_command(scope_t& scope, const string& verb);
void normalize_report_options(report_t& report, const string& verb);
void handle_debug_options(int argc, char * argv[]);
} // namespace ledger

View file

@ -103,10 +103,12 @@ class handler_t
public:
T * parent;
value_t value;
bool wants_arg;
handler_t(const char * _name, const char _ch = '\0')
: name(_name), name_len(std::strlen(name)), ch(_ch),
handled(false), parent(NULL), value() {
handled(false), parent(NULL), value(),
wants_arg(name[name_len - 1] == '_') {
TRACE_CTOR(handler_t, "const char *, const char");
}
handler_t(const handler_t& other)
@ -141,14 +143,18 @@ public:
return handled;
}
string str() const {
string& str() {
assert(handled);
return value.as_string();
return value.as_string_lval();
}
void on() {
handled = true;
}
void on(const char * str) {
handled = true;
value = string_value(str);
}
void on(const string& str) {
handled = true;
value = string_value(str);
@ -164,7 +170,7 @@ public:
}
virtual void handler(call_scope_t& args) {
if (name[name_len - 1] == '_')
if (wants_arg)
value = args[0];
}
@ -210,13 +216,17 @@ inline bool optcmp(const char * p, const char * n) {
CALL_FUNCTOR(name ## _handler))
#define OPT_(name) \
if (! *(p + 1) || (*(p + 1) == '_' && ! *(p + 2)) || \
if (! *(p + 1) || \
((name ## _handler).wants_arg && \
*(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))) \
if (! *(p + 1) || \
((name ## _handler).wants_arg && \
*(p + 1) == '_' && ! *(p + 2))) \
return ((name ## _handler).parent = this, \
CALL_FUNCTOR(name ## _handler))
@ -254,6 +264,13 @@ inline bool optcmp(const char * p, const char * n) {
} \
END(name)
#define OPTION__(type, name, body) \
BEGIN(type, name) \
{ \
body \
} \
END(name)
#define OPT_PREFIX "opt_"
#define OPT_PREFIX_LEN 4

View file

@ -88,7 +88,7 @@ int main(int argc, char * argv[], char * envp[])
// Look for options and a command verb in the command-line arguments
bind_scope_t bound_scope(*global_scope.get(), global_scope->report());
args = read_command_arguments(bound_scope, args);
args = global_scope->read_command_arguments(bound_scope, args);
if (global_scope->HANDLED(script_)) {
// Ledger is being invoked as a script command interpreter
@ -113,7 +113,7 @@ int main(int argc, char * argv[], char * envp[])
}
else {
// Commence the REPL by displaying the current Ledger version
global_scope->session().option_version(global_scope->session());
global_scope->show_version_info(std::cout);
global_scope->read_journal_files();

View file

@ -47,15 +47,15 @@ namespace {
else
*p++ = ch;
}
*p = '\0';
if (expr_t::ptr_op_t op = scope.lookup(buf))
return op_bool_tuple(op, false);
*p++ = '_';
*p = '\0';
return op_bool_tuple(scope.lookup(buf), true);
if (expr_t::ptr_op_t op = scope.lookup(buf))
return op_bool_tuple(op, true);
*--p = '\0';
return op_bool_tuple(scope.lookup(buf), false);
}
op_bool_tuple find_option(scope_t& scope, const char letter)
@ -63,15 +63,15 @@ namespace {
char buf[10];
std::strcpy(buf, "opt_");
buf[4] = letter;
buf[5] = '\0';
if (expr_t::ptr_op_t op = scope.lookup(buf))
return op_bool_tuple(op, false);
buf[5] = '_';
buf[6] = '\0';
return op_bool_tuple(scope.lookup(buf), true);
if (expr_t::ptr_op_t op = scope.lookup(buf))
return op_bool_tuple(op, true);
buf[5] = '\0';
return op_bool_tuple(scope.lookup(buf), false);
}
void process_option(const function_t& opt, scope_t& scope,

View file

@ -141,8 +141,8 @@ public:
}
bool should_display(account_t& account) {
if (! disp_pred.predicate && ! report.display_predicate.empty())
disp_pred.predicate.parse(report.display_predicate);
if (! disp_pred.predicate && report.HANDLED(display_))
disp_pred.predicate.parse(report.HANDLER(display_).str());
return disp_pred(account);
}

View file

@ -82,7 +82,7 @@ value_t eval_command(call_scope_t& args)
std::ostream& out(report.output_stream);
expr_t expr(*arg);
out << expr.calc(args).strip_annotations(report.what_to_keep)
out << expr.calc(args).strip_annotations(report.what_to_keep())
<< std::endl;
return 0L;
}

View file

@ -38,6 +38,45 @@
namespace ledger {
report_t::report_t(session_t& _session) : session(_session)
{
// Setup default values for some of the option handlers
HANDLER(date_format_).on("%y-%b-%d");
HANDLER(register_format_).on(
"%-.9(display_date) %-.20(payee)"
" %-.23(truncate(account, 23, 2))"
" %!12(print_balance(strip(display_amount), 12, 67))"
" %!12(print_balance(strip(display_total), 12, 80, true))\n%/"
"%31|%-.23(truncate(account, 23, 2))"
" %!12(print_balance(strip(display_amount), 12, 67))"
" %!12(print_balance(strip(display_total), 12, 80, true))\n");
// jww (2009-02-06): Most of these still need to be defined
HANDLER(wide_register_format_).on(
"%-.9D %-.35P %-.39A %22.108t %!22.132T\n%/"
"%48|%-.38A %22.108t %!22.132T\n");
HANDLER(print_format_).on(
"%(display_date)%(entry.cleared ? \" *\" : (entry.uncleared ? \"\" : \" !\"))"
"%(code ? \" (\" + code + \")\" : \"\") %(payee)%(entry.comment | \"\")\n"
" %(cleared ? \" *\" : (uncleared ? \"\" : \" !\"))%-34(account)"
" %12(amount)%(comment | \"\")\n%/"
" %(cleared ? \" *\" : (uncleared ? \"\" : \" !\"))%-34(account)"
" %12(amount)%(comment | \"\")\n%/\n");
HANDLER(balance_format_).on(
"%20(strip(display_total)) %(depth_spacer)%-(partial_account)\n");
HANDLER(equity_format_).on("\n%D %Y%C%P\n%/ %-34W %12t\n");
HANDLER(plot_amount_format_).on("%D %(S(t))\n");
HANDLER(plot_total_format_).on("%D %(S(T))\n");
HANDLER(write_hdr_format_).on("%d %Y%C%P\n");
HANDLER(write_xact_format_).on(" %-34W %12o%n\n");
HANDLER(prices_format_).on("%[%Y/%m/%d %H:%M:%S %Z] %-10A %12t %12T\n");
HANDLER(pricesdb_format_).on("P %[%Y/%m/%d %H:%M:%S] %A %t\n");
}
void report_t::xacts_report(xact_handler_ptr handler)
{
session_xacts_iterator walker(session);
@ -59,7 +98,7 @@ void report_t::sum_all_accounts()
(chain_xact_handlers(*this, xact_handler_ptr(new set_account_value), false),
walker);
session.master->calculate_sums(amount_expr, *this);
session.master->calculate_sums(HANDLER(amount_).expr, *this);
}
void report_t::accounts_report(acct_handler_ptr handler)
@ -69,11 +108,11 @@ void report_t::accounts_report(acct_handler_ptr handler)
if (! HANDLED(sort_)) {
basic_accounts_iterator walker(*session.master);
pass_down_accounts(handler, walker,
item_predicate<account_t>("total", what_to_keep));
item_predicate<account_t>("total", what_to_keep()));
} else {
sorted_accounts_iterator walker(*session.master, HANDLER(sort_).str());
pass_down_accounts(handler, walker,
item_predicate<account_t>("total", what_to_keep));
item_predicate<account_t>("total", what_to_keep()));
}
session.clean_xacts();
@ -86,17 +125,22 @@ void report_t::commodities_report(const string& format)
value_t report_t::fn_amount_expr(call_scope_t& scope)
{
return amount_expr.calc(scope);
return HANDLER(amount_).expr.calc(scope);
}
value_t report_t::fn_total_expr(call_scope_t& scope)
{
return total_expr.calc(scope);
return HANDLER(total_).expr.calc(scope);
}
value_t report_t::fn_display_amount(call_scope_t& scope)
{
return HANDLER(display_amount_).expr.calc(scope);
}
value_t report_t::fn_display_total(call_scope_t& scope)
{
return display_total.calc(scope);
return HANDLER(display_total_).expr.calc(scope);
}
namespace {
@ -131,15 +175,18 @@ namespace {
#endif
std::ostringstream out;
args[0].strip_annotations(report.what_to_keep)
.print(out, *first_width, *latter_width);
args[0].strip_annotations(report.what_to_keep())
.print(out, *first_width, *latter_width,
report.HANDLED(date_format_) ?
report.HANDLER(date_format_).str() : optional<string>());
return string_value(out.str());
}
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);
return args[0].strip_annotations(report.what_to_keep());
}
value_t fn_truncate(call_scope_t& args)
@ -166,9 +213,9 @@ namespace {
when = item.date();
}
if (report.HANDLED(output_date_format_))
return string_value
(format_date(when, report.HANDLER(output_date_format_).str()));
if (report.HANDLED(date_format_))
return string_value(format_date(when,
report.HANDLER(date_format_).str()));
else
return string_value(format_date(when));
}
@ -194,7 +241,8 @@ namespace {
(args_to_predicate_expr(args.value().as_sequence().begin(),
args.value().as_sequence().end()));
DEBUG("report.predicate", "Predicate = " << report.predicate);
DEBUG("report.predicate",
"Predicate = " << report.HANDLER(limit_).str());
(report.*report_method)(handler_ptr(handler));
@ -213,9 +261,6 @@ namespace {
// 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();
@ -233,20 +278,20 @@ expr_t::ptr_op_t report_t::lookup(const string& name)
std::strcmp(p, "balance") == 0)
return expr_t::op_t::wrap_functor
(reporter<account_t, acct_handler_ptr, &report_t::accounts_report>
(new format_accounts(*this, FORMAT(balance_format))));
(new format_accounts(*this, HANDLER(balance_format_).str())));
break;
case 'e':
if (std::strcmp(p, "equity") == 0)
return expr_t::op_t::wrap_functor
(reporter<account_t, acct_handler_ptr, &report_t::accounts_report>
(new format_equity(*this, FORMAT(print_format))));
(new format_equity(*this, HANDLER(print_format_).str())));
break;
case 'p':
if (*(p + 1) == '\0' || std::strcmp(p, "print") == 0)
return WRAP_FUNCTOR
(reporter<>(new format_xacts(*this, FORMAT(print_format))));
(reporter<>(new format_xacts(*this, HANDLER(print_format_).str())));
break;
case 'r':
@ -254,7 +299,7 @@ expr_t::ptr_op_t report_t::lookup(const string& name)
std::strcmp(p, "reg") == 0 ||
std::strcmp(p, "register") == 0)
return WRAP_FUNCTOR
(reporter<>(new format_xacts(*this, FORMAT(register_format))));
(reporter<>(new format_xacts(*this, HANDLER(register_format_).str())));
break;
}
}
@ -262,6 +307,7 @@ expr_t::ptr_op_t report_t::lookup(const string& name)
case 'd':
METHOD(report_t, display_total);
else METHOD(report_t, display_amount);
else FUNCTION(display_date);
break;
@ -275,6 +321,7 @@ expr_t::ptr_op_t report_t::lookup(const string& name)
case 'a':
OPT(amount_);
else OPT(anon);
else OPT(account_);
break;
case 'b':
@ -313,8 +360,7 @@ expr_t::ptr_op_t report_t::lookup(const string& name)
break;
case 'i':
OPT(input_date_format_);
else OPT(invert);
OPT(invert);
break;
case 'j':
@ -322,7 +368,7 @@ expr_t::ptr_op_t report_t::lookup(const string& name)
break;
case 'l':
OPT_(limit);
OPT_(limit_);
break;
case 'm':
@ -336,14 +382,12 @@ expr_t::ptr_op_t report_t::lookup(const string& name)
case 'o':
OPT_(output_);
else OPT(output_date_format_);
break;
case 'p':
OPT_(period_);
else OPT(period_sort_);
else OPT(price);
else OPT(price_db_);
else OPT(pager_);
break;

View file

@ -106,222 +106,174 @@ class report_t : public scope_t
public:
session_t& session;
string account;
output_stream_t output_stream;
keep_details_t what_to_keep;
uint_least8_t budget_flags;
expr_t amount_expr;
expr_t total_expr;
expr_t display_total;
string predicate;
string secondary_predicate;
string display_predicate;
string report_period;
string report_period_sort;
bool show_revalued;
bool show_revalued_only;
explicit report_t(session_t& _session)
: session(_session),
amount_expr("amount"),
total_expr("total"),
display_total("total_expr"),
show_revalued(false),
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(),
session(other.session),
account(other.account),
what_to_keep(other.what_to_keep),
budget_flags(other.budget_flags),
amount_expr(other.amount_expr),
total_expr(other.total_expr),
display_total(other.display_total),
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),
show_revalued(other.show_revalued),
show_revalued_only(other.show_revalued_only),
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(pager_, 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");
}
explicit report_t(session_t& _session);
virtual ~report_t() {
TRACE_DTOR(report_t);
output_stream.close();
}
//
// Actual report generation; this is why we're here...
//
void xacts_report(xact_handler_ptr handler);
void entry_report(xact_handler_ptr handler, entry_t& entry);
void sum_all_accounts();
void accounts_report(acct_handler_ptr handler);
void commodities_report(const string& format);
void sum_all_accounts();
value_t fn_amount_expr(call_scope_t& scope);
value_t fn_total_expr(call_scope_t& scope);
value_t fn_display_amount(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;
if (HANDLED(limit_))
HANDLER(limit_).on(string("(") + HANDLER(limit_).str() + ")&" + str);
else
HANDLER(limit_).on(str);
}
void append_display_predicate(const string& str) {
if (HANDLED(display_))
HANDLER(display_).on(string("(") + HANDLER(display_).str() + ")&" + str);
else
HANDLER(display_).on(str);
}
keep_details_t what_to_keep() {
return keep_details_t(HANDLED(lots) || HANDLED(lot_prices),
HANDLED(lots) || HANDLED(lot_dates),
HANDLED(lots) || HANDLED(lot_tags),
HANDLED(base));
}
virtual expr_t::ptr_op_t lookup(const string& name);
/**
* Option handlers
*/
OPTION(report_t, amount_);
OPTION(report_t, amount_data);
OPTION(report_t, account_);
OPTION(report_t, actual); // -L
OPTION(report_t, add_budget);
OPTION__
(report_t, amount_, // -t
expr_t expr;
CTOR(report_t, amount_) {
expr = "amount";
});
OPTION(report_t, amount_data); // -j
OPTION(report_t, anon);
OPTION(report_t, ansi);
OPTION(report_t, ansi_invert);
OPTION(report_t, average); // -A
OPTION(report_t, balance_format_);
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, pager_);
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) {
OPTION(report_t, basis); // -B
OPTION_(report_t, begin_, DO_(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 (! parent->predicate.empty())
parent->predicate += "&";
parent->predicate += "date>=[";
parent->predicate += to_iso_extended_string(interval.begin);
parent->predicate += "]";
string predicate =
"date>=[" + to_iso_extended_string(interval.begin) + "]";
parent->append_predicate(predicate);
});
OPTION_(report_t, end_, DO_(args) {
OPTION(report_t, budget);
OPTION(report_t, by_payee); // -P
OPTION(report_t, cache_);
OPTION(report_t, cleared); // -C
OPTION(report_t, code_as_payee);
OPTION(report_t, collapse); // -n
OPTION(report_t, comm_as_payee); // -x
OPTION(report_t, cost);
OPTION(report_t, current); // -c
OPTION(report_t, daily);
OPTION(report_t, date_format_); // -y
OPTION(report_t, descend_);
OPTION(report_t, descend_if_);
OPTION(report_t, deviation); // -D
OPTION(report_t, display_); // -d
OPTION__
(report_t, display_amount_,
expr_t expr;
CTOR(report_t, display_amount_) {
expr = "amount_expr";
});
OPTION__
(report_t, display_total_,
expr_t expr;
CTOR(report_t, display_total_) {
expr = "total_expr";
});
OPTION(report_t, dow);
OPTION(report_t, effective);
OPTION(report_t, empty); // -E
OPTION_(report_t, end_, DO_(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 (! parent->predicate.empty())
parent->predicate += "&";
parent->predicate += "date<[";
parent->predicate += to_iso_extended_string(interval.begin);
parent->predicate += "]";
string predicate =
"date<[" + to_iso_extended_string(interval.begin) + "]";
parent->append_predicate(predicate);
#if 0
terminus = interval.begin;
#endif
});
OPTION_(report_t, sort_, DO_(args) {
on(args[0].to_string());
OPTION(report_t, equity_format_);
OPTION(report_t, forecast_);
OPTION(report_t, format_); // -F
OPTION(report_t, gain); // -G
OPTION(report_t, head_);
OPTION(report_t, invert);
OPTION(report_t, limit_); // -l
OPTION(report_t, lot_dates);
OPTION(report_t, lot_prices);
OPTION(report_t, lot_tags);
OPTION(report_t, lots);
OPTION(report_t, market); // -V
OPTION(report_t, monthly); // -M
OPTION(report_t, only_);
OPTION(report_t, output_); // -o
OPTION(report_t, pager_);
OPTION(report_t, percentage); // -%
OPTION(report_t, performance); // -g
OPTION(report_t, period_); // -p
OPTION(report_t, period_sort_);
OPTION(report_t, plot_amount_format_);
OPTION(report_t, plot_total_format_);
OPTION(report_t, price); // -I
OPTION(report_t, price_exp_); // -Z
OPTION(report_t, prices_format_);
OPTION(report_t, pricesdb_format_);
OPTION(report_t, print_format_);
OPTION(report_t, quantity); // -O
OPTION(report_t, quarterly);
OPTION(report_t, real); // -R
OPTION(report_t, reconcile_);
OPTION(report_t, reconcile_date_);
OPTION(report_t, register_format_);
OPTION(report_t, related); // -r
OPTION(report_t, related_all);
OPTION(report_t, revalued);
OPTION(report_t, revalued_only);
OPTION(report_t, set_price_);
OPTION_(report_t, sort_, DO_(args) { // -S
on(args[0].to_string());
parent->HANDLER(sort_entries_).off();
parent->HANDLER(sort_all_).off();
});
@ -336,505 +288,27 @@ public:
parent->HANDLER(sort_all_).off();
});
#if 0
//////////////////////////////////////////////////////////////////////
//
// Basic options
value_t option_full_help(call_scope_t& args) { // H
option_full_help(std::cout);
throw int(0);
}
value_t option_help(call_scope_t& args) { // h
option_help(std::cout);
throw int(0);
}
value_t option_help_calc(call_scope_t& args) {
option_calc_help(std::cout);
throw int(0);
}
value_t option_help_disp(call_scope_t& args) {
option_disp_help(std::cout);
throw int(0);
}
value_t option_help_comm(call_scope_t& args) {
option_comm_help(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)
config->init_file = path;
else
throw_(std::invalid_argument,
"The init file '" << path << "' does not exist or is not readable");
}
value_t option_account(call_scope_t& args) { // a:
config->account = optarg;
}
//////////////////////////////////////////////////////////////////////
//
// Report filtering
value_t option_current(call_scope_t& args) { // c
if (! predicate.empty())
predicate += "&";
predicate += "date<=now";
return true;
}
value_t option_cleared(call_scope_t& args) { // C
if (! predicate.empty())
predicate += "&";
predicate += "cleared";
return true;
}
value_t option_uncleared(call_scope_t& args) { // U
if (! predicate.empty())
predicate += "&";
predicate += "!cleared";
return true;
}
#if 0
value_t option_real(call_scope_t& args) { // R
if (! report->predicate.empty())
report->predicate += "&";
report->predicate += "R";
}
value_t option_actual(call_scope_t& args) { // L
if (! report->predicate.empty())
report->predicate += "&";
report->predicate += "L";
}
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;
}
value_t option_lot_prices(call_scope_t& args) {
what_to_keep.keep_price = true;
}
value_t option_lot_dates(call_scope_t& args) {
what_to_keep.keep_date = true;
}
value_t option_lot_tags(call_scope_t& args) {
what_to_keep.keep_tag = true;
}
#endif
//////////////////////////////////////////////////////////////////////
//
// Output customization
#if 0
value_t option_balance_format(call_scope_t& args) { // :
config->balance_format = optarg;
}
value_t option_register_format(call_scope_t& args) { // :
config->register_format = optarg;
}
value_t option_wide_register_format(call_scope_t& args) { // :
config->wide_register_format = optarg;
}
value_t option_plot_amount_format(call_scope_t& args) { // :
config->plot_amount_format = optarg;
}
value_t option_plot_total_format(call_scope_t& args) { // :
config->plot_total_format = optarg;
}
value_t option_print_format(call_scope_t& args) { // :
config->print_format = optarg;
}
value_t option_write_hdr_format(call_scope_t& args) { // :
config->write_hdr_format = optarg;
}
value_t option_write_xact_format(call_scope_t& args) { // :
config->write_xact_format = optarg;
}
value_t option_equity_format(call_scope_t& args) { // :
config->equity_format = optarg;
}
value_t option_prices_format(call_scope_t& args) { // :
config->prices_format = optarg;
}
value_t option_wide(call_scope_t& args) { // w
config->register_format = config->wide_register_format;
}
#endif
value_t option_head_(call_scope_t& args) { // :
head_entries = *var_t<long>(args, 0);
return true;
}
value_t option_tail_(call_scope_t& args) { // :
tail_entries = *var_t<long>(args, 0);
return true;
}
#if 0
value_t option_truncate(call_scope_t& args) { // :
std::string style(optarg);
if (style == "leading")
format_t::elision_style = format_t::TRUNCATE_LEADING;
else if (style == "middle")
format_t::elision_style = format_t::TRUNCATE_MIDDLE;
else if (style == "trailing")
format_t::elision_style = format_t::TRUNCATE_TRAILING;
else if (style == "abbrev")
format_t::elision_style = format_t::ABBREVIATE;
}
value_t option_abbrev_len(call_scope_t& args) { // :
format_t::abbrev_length = std::atoi(optarg);
}
#endif
value_t option_empty(call_scope_t& args) { // E
show_empty = true;
return true;
}
value_t option_collapse(call_scope_t& args) { // n
show_collapsed = true;
return true;
}
value_t option_subtotal(call_scope_t& args) { // s
show_subtotal = true;
return true;
}
value_t option_totals(call_scope_t& args) {
show_totals = true;
return true;
}
value_t option_sort_(call_scope_t& args) { // S:
sort_string = args[0].to_string();
return true;
}
value_t option_sort_entries_(call_scope_t& args) {
sort_string = args[0].to_string();
entry_sort = true;
return true;
}
value_t option_sort_all_(call_scope_t& args) {
sort_string = args[0].to_string();
entry_sort = false;
sort_all = true;
return true;
}
value_t option_period_sort_(call_scope_t& args) { // :
sort_string = args[0].to_string();
entry_sort = true;
return true;
}
value_t option_related(call_scope_t& args) { // r
show_related = true;
return true;
}
#if 0
value_t option_descend(call_scope_t& args) {
std::string arg(optarg);
std::string::size_type beg = 0;
report->descend_expr = "";
for (std::string::size_type pos = arg.find(';');
pos != std::string::npos;
beg = pos + 1, pos = arg.find(';', beg))
report->descend_expr += (std::string("t=={") +
std::string(arg, beg, pos - beg) + "};");
report->descend_expr += (std::string("t=={") +
std::string(arg, beg) + "}");
}
value_t option_descend_if(call_scope_t& args) {
report->descend_expr = optarg;
}
#endif
value_t option_period_(call_scope_t& args) { // p:
if (report_period.empty()) {
report_period = args[0].to_string();
} else {
report_period += " ";
report_period += args[0].to_string();
}
// If the period gives a beginning and/or ending date, make sure to
// modify the calculation predicate (via the --begin and --end
// options) to take this into account.
interval_t interval(report_period);
if (is_valid(interval.begin)) {
if (! predicate.empty())
predicate += "&";
predicate += "date>=[";
predicate += to_iso_extended_string(interval.begin);
predicate += "]";
}
if (is_valid(interval.end)) {
if (! predicate.empty())
predicate += "&";
predicate += "date<[";
predicate += to_iso_extended_string(interval.end);
predicate += "]";
#if 0
terminus = interval.end;
#endif
}
return true;
}
value_t option_daily(call_scope_t& args) {
if (report_period.empty())
report_period = "daily";
else
report_period = string("daily ") + report_period;
return true;
}
value_t option_weekly(call_scope_t& args) { // W
if (report_period.empty())
report_period = "weekly";
else
report_period = string("weekly ") + report_period;
return true;
}
value_t option_monthly(call_scope_t& args) { // M
if (report_period.empty())
report_period = "monthly";
else
report_period = string("monthly ") + report_period;
return true;
}
value_t option_quarterly(call_scope_t& args) {
if (report_period.empty())
report_period = "quarterly";
else
report_period = string("quarterly ") + report_period;
return true;
}
value_t option_yearly(call_scope_t& args) { // Y
if (report_period.empty())
report_period = "yearly";
else
report_period = string("yearly ") + report_period;
return true;
}
value_t option_dow(call_scope_t& args) {
days_of_the_week = true;
return true;
}
value_t option_by_payee(call_scope_t& args) { // P
by_payee = true;
return true;
}
value_t option_comm_as_payee(call_scope_t& args) { // x
comm_as_payee = true;
return true;
}
value_t option_code_as_payee(call_scope_t& args) {
code_as_payee = true;
return true;
}
#if 0
value_t option_budget(call_scope_t& args) {
report->budget_flags = BUDGET_BUDGETED;
}
value_t option_add_budget(call_scope_t& args) {
report->budget_flags = BUDGET_BUDGETED | BUDGET_UNBUDGETED;
}
value_t option_unbudgeted(call_scope_t& args) {
report->budget_flags = BUDGET_UNBUDGETED;
}
value_t option_forecast(call_scope_t& args) { // :
report->forecast_limit = optarg;
}
value_t option_reconcile(call_scope_t& args) { // :
report->reconcile_balance = optarg;
}
value_t option_reconcile_date(call_scope_t& args) { // :
report->reconcile_date = optarg;
}
#endif
value_t option_limit_(call_scope_t& args) { // l:
append_predicate(args[0].as_string());
return true;
}
#if 0
value_t option_only(call_scope_t& args) { // :
if (! report->secondary_predicate.empty())
report->secondary_predicate += "&";
report->secondary_predicate += "(";
report->secondary_predicate += optarg;
report->secondary_predicate += ")";
}
value_t option_display(call_scope_t& args) { // d:
if (! report->display_predicate.empty())
report->display_predicate += "&";
report->display_predicate += "(";
report->display_predicate += optarg;
report->display_predicate += ")";
}
#endif
value_t option_amount_(call_scope_t& args) { // t:
_amount_expr = args[0].as_string();
return true;
}
value_t option_total_(call_scope_t& args) { // T:
_total_expr = args[0].as_string();
return true;
}
value_t option_amount_data(call_scope_t&) { // j
format_string = session.plot_amount_format;
return true;
}
value_t option_total_data(call_scope_t&) { // J
format_string = session.plot_total_format;
return true;
}
//////////////////////////////////////////////////////////////////////
//
// Commodity reporting
value_t option_base(call_scope_t& args) { // :
what_to_keep.keep_base = true;
return true;
}
value_t option_price_db_(call_scope_t& args) { // :
// jww (2009-01-31): This, and several of the other option handlers,
// should be in the session object.
session.price_db = args[0].as_string();
return true;
}
value_t option_price_exp_(call_scope_t& args) { // Z:
session.pricing_leeway = lexical_cast<long>(args[0].as_string()) * 60;
return true;
}
value_t option_download(call_scope_t& args) { // Q
session.download_quotes = true;
return true;
}
value_t option_quantity(call_scope_t& args) { // O
show_revalued = false;
_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";
return true;
}
value_t option_price(call_scope_t& args) { // I
show_revalued = false;
_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)";
return true;
}
#if 0
void parse_price_setting(const char * optarg)
{
char * equals = std::strchr(optarg, '=');
if (! equals)
return;
while (std::isspace(*optarg))
optarg++;
while (equals > optarg && std::isspace(*(equals - 1)))
equals--;
std::string symbol(optarg, 0, equals - optarg);
amount_t price(equals + 1);
if (commodity_t * commodity = commodity_t::find_or_create(symbol)) {
commodity->add_price(datetime_t::now, price);
#if 0
commodity->history()->bogus_time = datetime_t::now;
#endif
}
}
#endif
value_t option_anon(call_scope_t& args) {
anonymize = true;
return true;
}
#endif // 0
//
// Scope members
//
virtual expr_t::ptr_op_t lookup(const string& name);
OPTION(report_t, subtotal); // -s
OPTION(report_t, tail_);
OPTION__
(report_t, total_, // -T
expr_t expr;
CTOR(report_t, total_) {
expr = "total";
});
OPTION(report_t, total_data); // -J
OPTION(report_t, totals);
OPTION(report_t, truncate_);
OPTION(report_t, unbudgeted);
OPTION(report_t, uncleared); // -U
OPTION(report_t, weekly); // -W
OPTION(report_t, wide); // -w
OPTION(report_t, wide_register_format_);
OPTION(report_t, write_hdr_format_);
OPTION(report_t, write_xact_format_);
OPTION(report_t, yearly); // -Y
};
} // namespace ledger

View file

@ -37,16 +37,9 @@
namespace ledger {
#if 0
boost::mutex session_t::session_mutex;
#endif
void set_session_context(session_t * session)
{
if (session) {
#if 0
session_t::session_mutex.lock();
#endif
amount_t::initialize(session->commodity_pool);
// jww (2009-02-04): Is amount_t the right place for parse_conversion to
@ -59,84 +52,52 @@ void set_session_context(session_t * session)
else if (! session) {
value_t::shutdown();
amount_t::shutdown();
#if 0
session_t::session_mutex.unlock();
#endif
}
}
session_t::session_t()
: next_data_file_from_command_line(false),
saw_data_file_from_command_line(false),
next_price_db_from_command_line(false),
saw_price_db_from_command_line(false),
: flush_on_next_data_file(false),
register_format
("%-.9(display_date) %-.20(payee) %-.23(truncate(account, 23, 2)) %!12(print_balance(strip(amount_expr), 12, 67)) "
"%!12(print_balance(strip(display_total), 12, 80, true))\n%/"
"%31|%-.23(truncate(account, 23, 2)) %!12(print_balance(strip(amount_expr), 12, 67)) "
"%!12(print_balance(strip(display_total), 12, 80, true))\n"),
wide_register_format
("%-.9D %-.35P %-.39A %22.108t %!22.132T\n%/"
"%48|%-.38A %22.108t %!22.132T\n"),
print_format
("%(display_date)%(cleared ? \" *\" : (uncleared ? \"\" : \" !\"))%(code ? \" (\" + code + \")\" : \"\") %(payee)%(entry.comment | \"\")\n %-34(account) %12(amount)%(comment | \"\")\n%/ %-34(account) %12(amount)%(comment | \"\")\n%/\n"),
balance_format
("%20(strip(display_total)) %(depth_spacer)%-(partial_account)\n"),
equity_format
("\n%D %Y%C%P\n%/ %-34W %12t\n"),
plot_amount_format
("%D %(S(t))\n"),
plot_total_format
("%D %(S(T))\n"),
write_hdr_format
("%d %Y%C%P\n"),
write_xact_format
(" %-34W %12o%n\n"),
prices_format
("%[%Y/%m/%d %H:%M:%S %Z] %-10A %12t %12T\n"),
pricesdb_format
("P %[%Y/%m/%d %H:%M:%S] %A %t\n"),
pricing_leeway(24 * 3600),
current_year(CURRENT_DATE().year()),
download_quotes(false),
#if 0
elision_style(ABBREVIATE),
#endif
abbrev_length(2),
ansi_codes(false),
ansi_invert(false),
commodity_pool(new commodity_pool_t),
master(new account_t(NULL, ""))
{
TRACE_CTOR(session_t, "");
optional<path> home;
if (const char * home_var = std::getenv("HOME"))
home = home_var;
init_file = home ? *home / ".ledgerrc" : "./.ledgerrc";
price_db = home ? *home / ".pricedb" : "./.pricedb";
HANDLER(price_db_).on((path(home_var) / ".pricedb").string());
else
HANDLER(price_db_).on(path("./.pricedb").string());
register_parser(new textual_parser_t);
// Add time commodity conversions, so that timelog's may be parsed
// in terms of seconds, but reported as minutes or hours.
if (commodity_t * commodity = commodity_pool->create("s")) {
if (commodity_t * commodity = commodity_pool->create("s"))
commodity->add_flags(COMMODITY_BUILTIN | COMMODITY_NOMARKET);
} else {
else
assert(false);
}
}
session_t::~session_t()
journal_t * session_t::create_journal()
{
TRACE_DTOR(session_t);
journal_t * journal = new journal_t(master.get());
journals.push_back(journal);
return journal;
}
void session_t::close_journal(journal_t * journal)
{
for (ptr_list<journal_t>::iterator i = journals.begin();
i != journals.end();
i++)
if (&*i == journal) {
journals.erase(i);
return;
}
assert(false);
checked_delete(journal);
}
std::size_t session_t::read_journal(journal_t& journal,
@ -169,28 +130,10 @@ std::size_t session_t::read_journal(journal_t& journal,
return read_journal(journal, stream, pathname, master);
}
void session_t::read_init()
{
if (init_file && exists(*init_file)) {
TRACE_START(init, 1, "Read initialization file");
ifstream init(*init_file);
journal_t temp;
if (read_journal(temp, *init_file) > 0 ||
temp.auto_entries.size() > 0 || temp.period_entries.size() > 0) {
throw_(parse_error,
"Entries found in initialization file '" << init_file << "'");
}
TRACE_FINISH(init, 1);
}
}
std::size_t session_t::read_data(journal_t& journal,
const string& master_account)
{
if (data_files.empty())
if (HANDLER(file_).data_files.empty())
throw_(parse_error, "No journal file was specified (please use -f)");
std::size_t entry_count = 0;
@ -200,7 +143,7 @@ std::size_t session_t::read_data(journal_t& journal,
if (! master_account.empty())
acct = journal.find_account(master_account);
journal.price_db = price_db;
journal.price_db = HANDLER(price_db_).str();
if (journal.price_db && exists(*journal.price_db)) {
if (read_journal(journal, *journal.price_db)) {
throw_(parse_error, "Entries not allowed in price history file");
@ -210,7 +153,7 @@ std::size_t session_t::read_data(journal_t& journal,
}
foreach (const path& pathname, data_files) {
foreach (const path& pathname, HANDLER(file_).data_files) {
if (pathname == "-") {
journal.sources.push_back("/dev/stdin");
@ -247,6 +190,20 @@ std::size_t session_t::read_data(journal_t& journal,
return entry_count;
}
void session_t::unregister_parser(journal_t::parser_t * parser)
{
for (ptr_list<journal_t::parser_t>::iterator i = parsers.begin();
i != parsers.end();
i++) {
if (&*i == parser) {
parsers.erase(i);
return;
}
}
assert(false);
checked_delete(parser);
}
void session_t::clean_xacts()
{
session_xacts_iterator walker(*this);
@ -302,76 +259,32 @@ expr_t::ptr_op_t session_t::lookup(const string& name)
{
const char * p = name.c_str();
switch (*p) {
case 'b':
if (std::strcmp(p, "balance_format") == 0)
return expr_t::op_t::wrap_value(string_value(balance_format));
break;
case 'e':
if (std::strcmp(p, "equity_format") == 0)
return expr_t::op_t::wrap_value(string_value(equity_format));
break;
case 'p':
if (std::strcmp(p, "plot_amount_format") == 0)
return expr_t::op_t::wrap_value(string_value(plot_amount_format));
else if (std::strcmp(p, "plot_total_format") == 0)
return expr_t::op_t::wrap_value(string_value(plot_total_format));
else if (std::strcmp(p, "prices_format") == 0)
return expr_t::op_t::wrap_value(string_value(prices_format));
else if (std::strcmp(p, "pricesdb_format") == 0)
return expr_t::op_t::wrap_value(string_value(pricesdb_format));
else if (std::strcmp(p, "print_format") == 0)
return expr_t::op_t::wrap_value(string_value(print_format));
break;
case 'r':
if (std::strcmp(p, "register_format") == 0)
return expr_t::op_t::wrap_value(string_value(register_format));
break;
case 'w':
if (std::strcmp(p, "wide_register_format") == 0)
return expr_t::op_t::wrap_value(string_value(wide_register_format));
else if (std::strcmp(p, "write_hdr_format") == 0)
return expr_t::op_t::wrap_value(string_value(write_hdr_format));
else if (std::strcmp(p, "write_xact_format") == 0)
return expr_t::op_t::wrap_value(string_value(write_xact_format));
break;
case 'o':
if (std::strncmp(p, "opt_", 4) == 0) {
p = p + 4;
if (WANT_OPT()) { p += OPT_PREFIX_LEN;
switch (*p) {
case 'a':
OPT(abbrev_len_);
else OPT_(account_); // -a
break;
case 'd':
if (std::strcmp(p, "debug_") == 0)
return MAKE_FUNCTOR(session_t::option_debug_);
OPT(download); // -Q
break;
case 'f':
if ((*(p + 1) == '_' && ! *(p + 2)) ||
std::strcmp(p, "file_") == 0)
return MAKE_FUNCTOR(session_t::option_file_);
OPT_(file_); // -f
break;
case 't':
if (std::strcmp(p, "trace_") == 0)
return MAKE_FUNCTOR(session_t::option_trace_);
case 'i':
OPT(input_date_format_);
break;
case 'v':
if (! *(p + 1) || std::strcmp(p, "verbose") == 0)
return MAKE_FUNCTOR(session_t::option_verbose);
else if (std::strcmp(p, "version") == 0)
return MAKE_FUNCTOR(session_t::option_version);
else if (std::strcmp(p, "verify") == 0)
return MAKE_FUNCTOR(session_t::option_verify);
case 'p':
OPT(price_db_);
break;
case 'Q':
OPT_CH(download); // -Q
break;
}
}
break;
}
return expr_t::ptr_op_t();
}

View file

@ -64,66 +64,25 @@ class session_t : public noncopyable, public scope_t
friend void set_session_context(session_t * session);
public:
std::list<path> data_files;
bool next_data_file_from_command_line;
bool saw_data_file_from_command_line;
optional<path> init_file;
optional<path> price_db;
bool next_price_db_from_command_line;
bool saw_price_db_from_command_line;
string register_format;
string wide_register_format;
string print_format;
string balance_format;
string equity_format;
string plot_amount_format;
string plot_total_format;
string write_hdr_format;
string write_xact_format;
string prices_format;
string pricesdb_format;
std::size_t pricing_leeway;
int current_year;
bool download_quotes;
format_t::elision_style_t elision_style;
int abbrev_length;
bool ansi_codes;
bool ansi_invert;
bool flush_on_next_data_file;
int current_year;
shared_ptr<commodity_pool_t> commodity_pool;
ptr_list<journal_t::parser_t> parsers;
ptr_list<journal_t> journals;
scoped_ptr<account_t> master;
session_t();
virtual ~session_t();
explicit session_t();
virtual ~session_t() {
TRACE_DTOR(session_t);
}
void now_at_command_line(const bool truth) {
next_data_file_from_command_line = truth;
next_price_db_from_command_line = truth;
flush_on_next_data_file = true;
}
journal_t * create_journal() {
journal_t * journal = new journal_t(master.get());
journals.push_back(journal);
return journal;
}
void close_journal(journal_t * journal) {
for (ptr_list<journal_t>::iterator i = journals.begin();
i != journals.end();
i++)
if (&*i == journal) {
journals.erase(i);
return;
}
assert(false);
checked_delete(journal);
}
journal_t * create_journal();
void close_journal(journal_t * journal);
std::size_t read_journal(journal_t& journal,
std::istream& in,
@ -133,102 +92,47 @@ public:
const path& pathname,
account_t * master = NULL);
void read_init();
std::size_t read_data(journal_t& journal,
const string& master_account = "");
void register_parser(journal_t::parser_t * parser) {
parsers.push_back(parser);
}
void unregister_parser(journal_t::parser_t * parser) {
for (ptr_list<journal_t::parser_t>::iterator i = parsers.begin();
i != parsers.end();
i++)
if (&*i == parser) {
parsers.erase(i);
return;
}
assert(false);
checked_delete(parser);
}
//
// Dealing with accounts
//
void add_account(account_t * acct) {
master->add_account(acct);
}
bool remove_account(account_t * acct) {
return master->remove_account(acct);
}
void clean_accounts();
void unregister_parser(journal_t::parser_t * parser);
void clean_xacts();
void clean_xacts(entry_t& entry);
void clean_accounts();
void clean_all() {
clean_xacts();
clean_accounts();
}
//
// Scope members
//
virtual expr_t::ptr_op_t lookup(const string& name);
//
// Help options
//
/**
* Option handlers
*/
value_t option_version(scope_t&) {
std::cout << "Ledger " << ledger::version << ", the command-line accounting tool";
std::cout << "\n\nCopyright (c) 2003-2009, John Wiegley. All rights reserved.\n\n\
This program is made available under the terms of the BSD Public License.\n\
See LICENSE file included with the distribution for details and disclaimer.";
std::cout << std::endl;
return NULL_VALUE;
}
OPTION(session_t, abbrev_len_);
OPTION(session_t, account_); // -a
OPTION(session_t, download); // -Q
//
// Debug options
//
OPTION__
(session_t, file_, // -f
std::list<path> data_files;
CTOR(session_t, file_) {}
DO_(args) {
assert(args.size() == 1);
if (parent->flush_on_next_data_file) {
data_files.clear();
parent->flush_on_next_data_file = false;
}
data_files.push_back(args[0].as_string());
});
value_t option_trace_(scope_t&) {
return NULL_VALUE;
}
value_t option_debug_(scope_t&) {
return NULL_VALUE;
}
value_t option_verify(scope_t&) {
return NULL_VALUE;
}
value_t option_verbose(scope_t&) {
#if defined(LOGGING_ON)
if (_log_level < LOG_INFO)
_log_level = LOG_INFO;
#endif
return NULL_VALUE;
}
//
// Option handlers
//
value_t option_file_(call_scope_t& args) { // f
assert(args.size() == 1);
if (next_data_file_from_command_line &&
! saw_data_file_from_command_line) {
data_files.clear();
saw_data_file_from_command_line = true;
}
data_files.push_back(args[0].as_string());
return true;
}
OPTION(session_t, input_date_format_);
OPTION(session_t, price_db_);
};
/**

View file

@ -61,7 +61,7 @@ namespace ledger {
* Cline's "C++ FAQ Lite". Arguably this should be three different
* classes, but that introduces additional unneeded complications.
*/
class output_stream_t : public noncopyable
class output_stream_t
{
private:
int pipe_to_pager_fd;
@ -80,6 +80,16 @@ public:
TRACE_CTOR(output_stream_t, "");
}
/**
* When copy-constructed, make the copy just be a new output stream. This
* allows large classes to rely on their default copy-constructor without
* worrying about pointer copying within output_stream_t.
*/
output_stream_t(const output_stream_t& other)
: pipe_to_pager_fd(-1), os(&std::cout) {
TRACE_CTOR(output_stream_t, "copy");
}
/**
* Destroys an output_stream_t. This deletes the dynamically
* allocated ostream, if necessary. It also closes output file