Restored all the option handlers from 2.6.2, but not the options themselves.
This commit is contained in:
parent
ecc5a1aab5
commit
cf6babcf90
13 changed files with 547 additions and 1130 deletions
31
src/chain.cc
31
src/chain.cc
|
|
@ -55,10 +55,10 @@ xact_handler_ptr chain_xact_handlers(report_t& report,
|
||||||
|
|
||||||
// filter_xacts will only pass through xacts matching the
|
// filter_xacts will only pass through xacts matching the
|
||||||
// `display_predicate'.
|
// `display_predicate'.
|
||||||
if (! report.display_predicate.empty())
|
if (report.HANDLED(display_))
|
||||||
handler.reset(new filter_xacts
|
handler.reset(new filter_xacts
|
||||||
(handler, item_predicate<xact_t>(report.display_predicate,
|
(handler, item_predicate<xact_t>(report.HANDLER(display_).str(),
|
||||||
report.what_to_keep)));
|
report.what_to_keep())));
|
||||||
|
|
||||||
// calc_xacts computes the running total. When this appears will
|
// calc_xacts computes the running total. When this appears will
|
||||||
// determine, for example, whether filtered xacts are included or excluded
|
// determine, for example, whether filtered xacts are included or excluded
|
||||||
|
|
@ -86,7 +86,7 @@ xact_handler_ptr chain_xact_handlers(report_t& report,
|
||||||
i++)
|
i++)
|
||||||
handler.reset(new component_xacts
|
handler.reset(new component_xacts
|
||||||
(handler,
|
(handler,
|
||||||
item_predicate<xact_t>(*i, report.what_to_keep)));
|
item_predicate<xact_t>(*i, report.what_to_keep())));
|
||||||
|
|
||||||
remember_components = true;
|
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
|
// filter_xacts will only pass through xacts matching the
|
||||||
// `secondary_predicate'.
|
// `secondary_predicate'.
|
||||||
if (! report.secondary_predicate.empty())
|
if (report.HANDLED(only_))
|
||||||
handler.reset(new filter_xacts
|
handler.reset(new filter_xacts
|
||||||
(handler, item_predicate<xact_t>
|
(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'
|
// sort_xacts will sort all the xacts it sees, based on the `sort_order'
|
||||||
// value expression.
|
// 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
|
// changed_value_xacts adds virtual xacts to the list to account for
|
||||||
// changes in market value of commodities, which otherwise would affect
|
// changes in market value of commodities, which otherwise would affect
|
||||||
// the running total unpredictably.
|
// the running total unpredictably.
|
||||||
if (report.show_revalued)
|
if (report.HANDLED(revalued))
|
||||||
handler.reset(new changed_value_xacts(handler, report.total_expr,
|
handler.reset(new changed_value_xacts(handler,
|
||||||
report.show_revalued_only));
|
report.HANDLER(total_).expr,
|
||||||
|
report.HANDLED(revalued_only)));
|
||||||
|
|
||||||
// collapse_xacts causes entries with multiple xacts to appear as entries
|
// collapse_xacts causes entries with multiple xacts to appear as entries
|
||||||
// with a subtotaled xact for each commodity used.
|
// 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
|
// interval_xacts groups xacts together based on a time period, such as
|
||||||
// weekly or monthly.
|
// weekly or monthly.
|
||||||
if (! report.report_period.empty()) {
|
if (report.HANDLED(period_)) {
|
||||||
handler.reset(new interval_xacts(handler, report.report_period,
|
handler.reset(new interval_xacts(handler, report.HANDLER(period_).str(),
|
||||||
remember_components));
|
remember_components));
|
||||||
handler.reset(new sort_xacts(handler, "d"));
|
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));
|
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()) {
|
if (report.HANDLED(limit_)) {
|
||||||
DEBUG("report.predicate",
|
DEBUG("report.predicate",
|
||||||
"Report predicate expression = " << report.predicate);
|
"Report predicate expression = " << report.HANDLER(limit_).str());
|
||||||
handler.reset(new filter_xacts
|
handler.reset(new filter_xacts
|
||||||
(handler, item_predicate<xact_t>(report.predicate,
|
(handler, item_predicate<xact_t>(report.HANDLER(limit_).str(),
|
||||||
report.what_to_keep)));
|
report.what_to_keep())));
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
|
|
|
||||||
262
src/global.cc
262
src/global.cc
|
|
@ -61,8 +61,8 @@ global_scope_t::global_scope_t(char ** envp)
|
||||||
// that such options are beginning, since options like -f cause a complete
|
// that such options are beginning, since options like -f cause a complete
|
||||||
// override of files found anywhere else.
|
// override of files found anywhere else.
|
||||||
session().now_at_command_line(false);
|
session().now_at_command_line(false);
|
||||||
read_environment_settings(report(), envp);
|
read_environment_settings(envp);
|
||||||
session().read_init();
|
read_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
global_scope_t::~global_scope_t()
|
global_scope_t::~global_scope_t()
|
||||||
|
|
@ -76,12 +76,37 @@ global_scope_t::~global_scope_t()
|
||||||
IF_VERIFY() set_session_context(NULL);
|
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()
|
void global_scope_t::read_journal_files()
|
||||||
{
|
{
|
||||||
INFO_START(journal, "Read journal file");
|
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(),
|
std::size_t count = session().read_data(*session().create_journal(),
|
||||||
report().account);
|
master_account);
|
||||||
if (count == 0)
|
if (count == 0)
|
||||||
throw_(parse_error, "Failed to locate any journal entries; "
|
throw_(parse_error, "Failed to locate any journal entries; "
|
||||||
"did you specify a valid file with -f?");
|
"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,
|
// 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...
|
// 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
|
// 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;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
|
||||||
}
|
|
||||||
|
|
||||||
expr_t::ptr_op_t global_scope_t::lookup(const string& name)
|
expr_t::ptr_op_t global_scope_t::lookup(const string& name)
|
||||||
{
|
{
|
||||||
const char * p = name.c_str();
|
const char * p = name.c_str();
|
||||||
|
|
@ -224,6 +246,9 @@ expr_t::ptr_op_t global_scope_t::lookup(const string& name)
|
||||||
case 'd':
|
case 'd':
|
||||||
OPT(debug_);
|
OPT(debug_);
|
||||||
break;
|
break;
|
||||||
|
case 'i':
|
||||||
|
OPT(init_file_);
|
||||||
|
break;
|
||||||
case 's':
|
case 's':
|
||||||
OPT(script_);
|
OPT(script_);
|
||||||
break;
|
break;
|
||||||
|
|
@ -233,6 +258,7 @@ expr_t::ptr_op_t global_scope_t::lookup(const string& name)
|
||||||
case 'v':
|
case 'v':
|
||||||
OPT_(verbose);
|
OPT_(verbose);
|
||||||
else OPT(verify);
|
else OPT(verify);
|
||||||
|
else OPT(version);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -254,6 +280,118 @@ expr_t::ptr_op_t global_scope_t::lookup(const string& name)
|
||||||
return expr_t::ptr_op_t();
|
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[])
|
void handle_debug_options(int argc, char * argv[])
|
||||||
{
|
{
|
||||||
for (int i = 1; i < argc; i++) {
|
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
|
} // namespace ledger
|
||||||
|
|
|
||||||
40
src/global.h
40
src/global.h
|
|
@ -51,7 +51,14 @@ public:
|
||||||
global_scope_t(char ** envp);
|
global_scope_t(char ** envp);
|
||||||
~global_scope_t();
|
~global_scope_t();
|
||||||
|
|
||||||
|
void read_init();
|
||||||
void read_journal_files();
|
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();
|
char * prompt_string();
|
||||||
|
|
||||||
|
|
@ -92,22 +99,41 @@ public:
|
||||||
return true;
|
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, 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, script_);
|
||||||
OPTION(global_scope_t, trace_);
|
OPTION(global_scope_t, trace_);
|
||||||
OPTION(global_scope_t, verbose);
|
OPTION(global_scope_t, verbose);
|
||||||
OPTION(global_scope_t, verify);
|
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 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);
|
|
||||||
|
|
||||||
} // namespace ledger
|
} // namespace ledger
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -103,10 +103,12 @@ class handler_t
|
||||||
public:
|
public:
|
||||||
T * parent;
|
T * parent;
|
||||||
value_t value;
|
value_t value;
|
||||||
|
bool wants_arg;
|
||||||
|
|
||||||
handler_t(const char * _name, const char _ch = '\0')
|
handler_t(const char * _name, const char _ch = '\0')
|
||||||
: name(_name), name_len(std::strlen(name)), ch(_ch),
|
: name(_name), name_len(std::strlen(name)), ch(_ch),
|
||||||
handled(false), parent(NULL), value() {
|
handled(false), parent(NULL), value(),
|
||||||
|
wants_arg(name[name_len - 1] == '_') {
|
||||||
TRACE_CTOR(handler_t, "const char *, const char");
|
TRACE_CTOR(handler_t, "const char *, const char");
|
||||||
}
|
}
|
||||||
handler_t(const handler_t& other)
|
handler_t(const handler_t& other)
|
||||||
|
|
@ -141,14 +143,18 @@ public:
|
||||||
return handled;
|
return handled;
|
||||||
}
|
}
|
||||||
|
|
||||||
string str() const {
|
string& str() {
|
||||||
assert(handled);
|
assert(handled);
|
||||||
return value.as_string();
|
return value.as_string_lval();
|
||||||
}
|
}
|
||||||
|
|
||||||
void on() {
|
void on() {
|
||||||
handled = true;
|
handled = true;
|
||||||
}
|
}
|
||||||
|
void on(const char * str) {
|
||||||
|
handled = true;
|
||||||
|
value = string_value(str);
|
||||||
|
}
|
||||||
void on(const string& str) {
|
void on(const string& str) {
|
||||||
handled = true;
|
handled = true;
|
||||||
value = string_value(str);
|
value = string_value(str);
|
||||||
|
|
@ -164,7 +170,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void handler(call_scope_t& args) {
|
virtual void handler(call_scope_t& args) {
|
||||||
if (name[name_len - 1] == '_')
|
if (wants_arg)
|
||||||
value = args[0];
|
value = args[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -210,13 +216,17 @@ inline bool optcmp(const char * p, const char * n) {
|
||||||
CALL_FUNCTOR(name ## _handler))
|
CALL_FUNCTOR(name ## _handler))
|
||||||
|
|
||||||
#define OPT_(name) \
|
#define OPT_(name) \
|
||||||
if (! *(p + 1) || (*(p + 1) == '_' && ! *(p + 2)) || \
|
if (! *(p + 1) || \
|
||||||
|
((name ## _handler).wants_arg && \
|
||||||
|
*(p + 1) == '_' && ! *(p + 2)) || \
|
||||||
optcmp(p, #name)) \
|
optcmp(p, #name)) \
|
||||||
return ((name ## _handler).parent = this, \
|
return ((name ## _handler).parent = this, \
|
||||||
CALL_FUNCTOR(name ## _handler))
|
CALL_FUNCTOR(name ## _handler))
|
||||||
|
|
||||||
#define OPT_CH(name) \
|
#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, \
|
return ((name ## _handler).parent = this, \
|
||||||
CALL_FUNCTOR(name ## _handler))
|
CALL_FUNCTOR(name ## _handler))
|
||||||
|
|
||||||
|
|
@ -254,6 +264,13 @@ inline bool optcmp(const char * p, const char * n) {
|
||||||
} \
|
} \
|
||||||
END(name)
|
END(name)
|
||||||
|
|
||||||
|
#define OPTION__(type, name, body) \
|
||||||
|
BEGIN(type, name) \
|
||||||
|
{ \
|
||||||
|
body \
|
||||||
|
} \
|
||||||
|
END(name)
|
||||||
|
|
||||||
#define OPT_PREFIX "opt_"
|
#define OPT_PREFIX "opt_"
|
||||||
#define OPT_PREFIX_LEN 4
|
#define OPT_PREFIX_LEN 4
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -88,7 +88,7 @@ int main(int argc, char * argv[], char * envp[])
|
||||||
// Look for options and a command verb in the command-line arguments
|
// Look for options and a command verb in the command-line arguments
|
||||||
bind_scope_t bound_scope(*global_scope.get(), global_scope->report());
|
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_)) {
|
if (global_scope->HANDLED(script_)) {
|
||||||
// Ledger is being invoked as a script command interpreter
|
// Ledger is being invoked as a script command interpreter
|
||||||
|
|
@ -113,7 +113,7 @@ int main(int argc, char * argv[], char * envp[])
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Commence the REPL by displaying the current Ledger version
|
// 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();
|
global_scope->read_journal_files();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -47,15 +47,15 @@ namespace {
|
||||||
else
|
else
|
||||||
*p++ = ch;
|
*p++ = ch;
|
||||||
}
|
}
|
||||||
*p = '\0';
|
|
||||||
|
|
||||||
if (expr_t::ptr_op_t op = scope.lookup(buf))
|
|
||||||
return op_bool_tuple(op, false);
|
|
||||||
|
|
||||||
*p++ = '_';
|
*p++ = '_';
|
||||||
*p = '\0';
|
*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)
|
op_bool_tuple find_option(scope_t& scope, const char letter)
|
||||||
|
|
@ -63,15 +63,15 @@ namespace {
|
||||||
char buf[10];
|
char buf[10];
|
||||||
std::strcpy(buf, "opt_");
|
std::strcpy(buf, "opt_");
|
||||||
buf[4] = letter;
|
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[5] = '_';
|
||||||
buf[6] = '\0';
|
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,
|
void process_option(const function_t& opt, scope_t& scope,
|
||||||
|
|
|
||||||
|
|
@ -141,8 +141,8 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
bool should_display(account_t& account) {
|
bool should_display(account_t& account) {
|
||||||
if (! disp_pred.predicate && ! report.display_predicate.empty())
|
if (! disp_pred.predicate && report.HANDLED(display_))
|
||||||
disp_pred.predicate.parse(report.display_predicate);
|
disp_pred.predicate.parse(report.HANDLER(display_).str());
|
||||||
return disp_pred(account);
|
return disp_pred(account);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -82,7 +82,7 @@ value_t eval_command(call_scope_t& args)
|
||||||
std::ostream& out(report.output_stream);
|
std::ostream& out(report.output_stream);
|
||||||
|
|
||||||
expr_t expr(*arg);
|
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;
|
<< std::endl;
|
||||||
return 0L;
|
return 0L;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,45 @@
|
||||||
|
|
||||||
namespace ledger {
|
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)
|
void report_t::xacts_report(xact_handler_ptr handler)
|
||||||
{
|
{
|
||||||
session_xacts_iterator walker(session);
|
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),
|
(chain_xact_handlers(*this, xact_handler_ptr(new set_account_value), false),
|
||||||
walker);
|
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)
|
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_)) {
|
if (! HANDLED(sort_)) {
|
||||||
basic_accounts_iterator walker(*session.master);
|
basic_accounts_iterator walker(*session.master);
|
||||||
pass_down_accounts(handler, walker,
|
pass_down_accounts(handler, walker,
|
||||||
item_predicate<account_t>("total", what_to_keep));
|
item_predicate<account_t>("total", what_to_keep()));
|
||||||
} else {
|
} else {
|
||||||
sorted_accounts_iterator walker(*session.master, HANDLER(sort_).str());
|
sorted_accounts_iterator walker(*session.master, HANDLER(sort_).str());
|
||||||
pass_down_accounts(handler, walker,
|
pass_down_accounts(handler, walker,
|
||||||
item_predicate<account_t>("total", what_to_keep));
|
item_predicate<account_t>("total", what_to_keep()));
|
||||||
}
|
}
|
||||||
|
|
||||||
session.clean_xacts();
|
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)
|
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)
|
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)
|
value_t report_t::fn_display_total(call_scope_t& scope)
|
||||||
{
|
{
|
||||||
return display_total.calc(scope);
|
return HANDLER(display_total_).expr.calc(scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
@ -131,15 +175,18 @@ namespace {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
std::ostringstream out;
|
std::ostringstream out;
|
||||||
args[0].strip_annotations(report.what_to_keep)
|
args[0].strip_annotations(report.what_to_keep())
|
||||||
.print(out, *first_width, *latter_width);
|
.print(out, *first_width, *latter_width,
|
||||||
|
report.HANDLED(date_format_) ?
|
||||||
|
report.HANDLER(date_format_).str() : optional<string>());
|
||||||
|
|
||||||
return string_value(out.str());
|
return string_value(out.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
value_t fn_strip(call_scope_t& args)
|
value_t fn_strip(call_scope_t& args)
|
||||||
{
|
{
|
||||||
report_t& report(find_scope<report_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)
|
value_t fn_truncate(call_scope_t& args)
|
||||||
|
|
@ -166,9 +213,9 @@ namespace {
|
||||||
when = item.date();
|
when = item.date();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (report.HANDLED(output_date_format_))
|
if (report.HANDLED(date_format_))
|
||||||
return string_value
|
return string_value(format_date(when,
|
||||||
(format_date(when, report.HANDLER(output_date_format_).str()));
|
report.HANDLER(date_format_).str()));
|
||||||
else
|
else
|
||||||
return string_value(format_date(when));
|
return string_value(format_date(when));
|
||||||
}
|
}
|
||||||
|
|
@ -194,7 +241,8 @@ namespace {
|
||||||
(args_to_predicate_expr(args.value().as_sequence().begin(),
|
(args_to_predicate_expr(args.value().as_sequence().begin(),
|
||||||
args.value().as_sequence().end()));
|
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));
|
(report.*report_method)(handler_ptr(handler));
|
||||||
|
|
||||||
|
|
@ -213,9 +261,6 @@ namespace {
|
||||||
// emacs | lisp
|
// emacs | lisp
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define FORMAT(member) \
|
|
||||||
(HANDLED(format_) ? HANDLER(format_).str() : session.member)
|
|
||||||
|
|
||||||
expr_t::ptr_op_t report_t::lookup(const string& name)
|
expr_t::ptr_op_t report_t::lookup(const string& name)
|
||||||
{
|
{
|
||||||
const char * p = name.c_str();
|
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)
|
std::strcmp(p, "balance") == 0)
|
||||||
return expr_t::op_t::wrap_functor
|
return expr_t::op_t::wrap_functor
|
||||||
(reporter<account_t, acct_handler_ptr, &report_t::accounts_report>
|
(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;
|
break;
|
||||||
|
|
||||||
case 'e':
|
case 'e':
|
||||||
if (std::strcmp(p, "equity") == 0)
|
if (std::strcmp(p, "equity") == 0)
|
||||||
return expr_t::op_t::wrap_functor
|
return expr_t::op_t::wrap_functor
|
||||||
(reporter<account_t, acct_handler_ptr, &report_t::accounts_report>
|
(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;
|
break;
|
||||||
|
|
||||||
case 'p':
|
case 'p':
|
||||||
if (*(p + 1) == '\0' || std::strcmp(p, "print") == 0)
|
if (*(p + 1) == '\0' || std::strcmp(p, "print") == 0)
|
||||||
return WRAP_FUNCTOR
|
return WRAP_FUNCTOR
|
||||||
(reporter<>(new format_xacts(*this, FORMAT(print_format))));
|
(reporter<>(new format_xacts(*this, HANDLER(print_format_).str())));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'r':
|
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, "reg") == 0 ||
|
||||||
std::strcmp(p, "register") == 0)
|
std::strcmp(p, "register") == 0)
|
||||||
return WRAP_FUNCTOR
|
return WRAP_FUNCTOR
|
||||||
(reporter<>(new format_xacts(*this, FORMAT(register_format))));
|
(reporter<>(new format_xacts(*this, HANDLER(register_format_).str())));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -262,6 +307,7 @@ expr_t::ptr_op_t report_t::lookup(const string& name)
|
||||||
|
|
||||||
case 'd':
|
case 'd':
|
||||||
METHOD(report_t, display_total);
|
METHOD(report_t, display_total);
|
||||||
|
else METHOD(report_t, display_amount);
|
||||||
else FUNCTION(display_date);
|
else FUNCTION(display_date);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -275,6 +321,7 @@ expr_t::ptr_op_t report_t::lookup(const string& name)
|
||||||
case 'a':
|
case 'a':
|
||||||
OPT(amount_);
|
OPT(amount_);
|
||||||
else OPT(anon);
|
else OPT(anon);
|
||||||
|
else OPT(account_);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'b':
|
case 'b':
|
||||||
|
|
@ -313,8 +360,7 @@ expr_t::ptr_op_t report_t::lookup(const string& name)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'i':
|
case 'i':
|
||||||
OPT(input_date_format_);
|
OPT(invert);
|
||||||
else OPT(invert);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'j':
|
case 'j':
|
||||||
|
|
@ -322,7 +368,7 @@ expr_t::ptr_op_t report_t::lookup(const string& name)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'l':
|
case 'l':
|
||||||
OPT_(limit);
|
OPT_(limit_);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'm':
|
case 'm':
|
||||||
|
|
@ -336,14 +382,12 @@ expr_t::ptr_op_t report_t::lookup(const string& name)
|
||||||
|
|
||||||
case 'o':
|
case 'o':
|
||||||
OPT_(output_);
|
OPT_(output_);
|
||||||
else OPT(output_date_format_);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'p':
|
case 'p':
|
||||||
OPT_(period_);
|
OPT_(period_);
|
||||||
else OPT(period_sort_);
|
else OPT(period_sort_);
|
||||||
else OPT(price);
|
else OPT(price);
|
||||||
else OPT(price_db_);
|
|
||||||
else OPT(pager_);
|
else OPT(pager_);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
||||||
818
src/report.h
818
src/report.h
|
|
@ -106,221 +106,173 @@ class report_t : public scope_t
|
||||||
|
|
||||||
public:
|
public:
|
||||||
session_t& session;
|
session_t& session;
|
||||||
string account;
|
|
||||||
output_stream_t output_stream;
|
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() {
|
virtual ~report_t() {
|
||||||
TRACE_DTOR(report_t);
|
|
||||||
output_stream.close();
|
output_stream.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
// Actual report generation; this is why we're here...
|
|
||||||
//
|
|
||||||
|
|
||||||
void xacts_report(xact_handler_ptr handler);
|
void xacts_report(xact_handler_ptr handler);
|
||||||
void entry_report(xact_handler_ptr handler, entry_t& entry);
|
void entry_report(xact_handler_ptr handler, entry_t& entry);
|
||||||
void sum_all_accounts();
|
|
||||||
void accounts_report(acct_handler_ptr handler);
|
void accounts_report(acct_handler_ptr handler);
|
||||||
void commodities_report(const string& format);
|
void commodities_report(const string& format);
|
||||||
|
|
||||||
|
void sum_all_accounts();
|
||||||
|
|
||||||
value_t fn_amount_expr(call_scope_t& scope);
|
value_t fn_amount_expr(call_scope_t& scope);
|
||||||
value_t fn_total_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);
|
value_t fn_display_total(call_scope_t& scope);
|
||||||
|
|
||||||
void append_predicate(const string& str) {
|
void append_predicate(const string& str) {
|
||||||
if (! predicate.empty())
|
if (HANDLED(limit_))
|
||||||
predicate = string("(") + predicate + ")&";
|
HANDLER(limit_).on(string("(") + HANDLER(limit_).str() + ")&" + str);
|
||||||
predicate += 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 handlers
|
||||||
*/
|
*/
|
||||||
|
|
||||||
OPTION(report_t, amount_);
|
OPTION(report_t, account_);
|
||||||
OPTION(report_t, amount_data);
|
OPTION(report_t, actual); // -L
|
||||||
OPTION(report_t, anon);
|
OPTION(report_t, add_budget);
|
||||||
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, 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, basis); // -B
|
||||||
|
|
||||||
|
OPTION_(report_t, begin_, DO_(args) { // -b
|
||||||
interval_t interval(args[0].to_string());
|
interval_t interval(args[0].to_string());
|
||||||
if (! is_valid(interval.begin))
|
if (! is_valid(interval.begin))
|
||||||
throw_(std::invalid_argument,
|
throw_(std::invalid_argument,
|
||||||
"Could not determine beginning of period '"
|
"Could not determine beginning of period '"
|
||||||
<< args[0].to_string() << "'");
|
<< args[0].to_string() << "'");
|
||||||
|
|
||||||
if (! parent->predicate.empty())
|
string predicate =
|
||||||
parent->predicate += "&";
|
"date>=[" + to_iso_extended_string(interval.begin) + "]";
|
||||||
parent->predicate += "date>=[";
|
parent->append_predicate(predicate);
|
||||||
parent->predicate += to_iso_extended_string(interval.begin);
|
|
||||||
parent->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());
|
interval_t interval(args[0].to_string());
|
||||||
if (! is_valid(interval.begin))
|
if (! is_valid(interval.begin))
|
||||||
throw_(std::invalid_argument,
|
throw_(std::invalid_argument,
|
||||||
"Could not determine end of period '"
|
"Could not determine end of period '"
|
||||||
<< args[0].to_string() << "'");
|
<< args[0].to_string() << "'");
|
||||||
|
|
||||||
if (! parent->predicate.empty())
|
string predicate =
|
||||||
parent->predicate += "&";
|
"date<[" + to_iso_extended_string(interval.begin) + "]";
|
||||||
parent->predicate += "date<[";
|
parent->append_predicate(predicate);
|
||||||
parent->predicate += to_iso_extended_string(interval.begin);
|
|
||||||
parent->predicate += "]";
|
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
terminus = interval.begin;
|
terminus = interval.begin;
|
||||||
#endif
|
#endif
|
||||||
});
|
});
|
||||||
|
|
||||||
OPTION_(report_t, sort_, DO_(args) {
|
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());
|
on(args[0].to_string());
|
||||||
parent->HANDLER(sort_entries_).off();
|
parent->HANDLER(sort_entries_).off();
|
||||||
parent->HANDLER(sort_all_).off();
|
parent->HANDLER(sort_all_).off();
|
||||||
|
|
@ -336,505 +288,27 @@ public:
|
||||||
parent->HANDLER(sort_all_).off();
|
parent->HANDLER(sort_all_).off();
|
||||||
});
|
});
|
||||||
|
|
||||||
#if 0
|
OPTION(report_t, subtotal); // -s
|
||||||
//////////////////////////////////////////////////////////////////////
|
OPTION(report_t, tail_);
|
||||||
//
|
|
||||||
// Basic options
|
OPTION__
|
||||||
|
(report_t, total_, // -T
|
||||||
value_t option_full_help(call_scope_t& args) { // H
|
expr_t expr;
|
||||||
option_full_help(std::cout);
|
CTOR(report_t, total_) {
|
||||||
throw int(0);
|
expr = "total";
|
||||||
}
|
});
|
||||||
|
|
||||||
value_t option_help(call_scope_t& args) { // h
|
OPTION(report_t, total_data); // -J
|
||||||
option_help(std::cout);
|
OPTION(report_t, totals);
|
||||||
throw int(0);
|
OPTION(report_t, truncate_);
|
||||||
}
|
OPTION(report_t, unbudgeted);
|
||||||
|
OPTION(report_t, uncleared); // -U
|
||||||
value_t option_help_calc(call_scope_t& args) {
|
OPTION(report_t, weekly); // -W
|
||||||
option_calc_help(std::cout);
|
OPTION(report_t, wide); // -w
|
||||||
throw int(0);
|
OPTION(report_t, wide_register_format_);
|
||||||
}
|
OPTION(report_t, write_hdr_format_);
|
||||||
|
OPTION(report_t, write_xact_format_);
|
||||||
value_t option_help_disp(call_scope_t& args) {
|
OPTION(report_t, yearly); // -Y
|
||||||
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);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ledger
|
} // namespace ledger
|
||||||
|
|
|
||||||
195
src/session.cc
195
src/session.cc
|
|
@ -37,16 +37,9 @@
|
||||||
|
|
||||||
namespace ledger {
|
namespace ledger {
|
||||||
|
|
||||||
#if 0
|
|
||||||
boost::mutex session_t::session_mutex;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void set_session_context(session_t * session)
|
void set_session_context(session_t * session)
|
||||||
{
|
{
|
||||||
if (session) {
|
if (session) {
|
||||||
#if 0
|
|
||||||
session_t::session_mutex.lock();
|
|
||||||
#endif
|
|
||||||
amount_t::initialize(session->commodity_pool);
|
amount_t::initialize(session->commodity_pool);
|
||||||
|
|
||||||
// jww (2009-02-04): Is amount_t the right place for parse_conversion to
|
// 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) {
|
else if (! session) {
|
||||||
value_t::shutdown();
|
value_t::shutdown();
|
||||||
amount_t::shutdown();
|
amount_t::shutdown();
|
||||||
#if 0
|
|
||||||
session_t::session_mutex.unlock();
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
session_t::session_t()
|
session_t::session_t()
|
||||||
: next_data_file_from_command_line(false),
|
: flush_on_next_data_file(false),
|
||||||
saw_data_file_from_command_line(false),
|
|
||||||
next_price_db_from_command_line(false),
|
|
||||||
saw_price_db_from_command_line(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()),
|
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),
|
commodity_pool(new commodity_pool_t),
|
||||||
master(new account_t(NULL, ""))
|
master(new account_t(NULL, ""))
|
||||||
{
|
{
|
||||||
TRACE_CTOR(session_t, "");
|
TRACE_CTOR(session_t, "");
|
||||||
|
|
||||||
optional<path> home;
|
|
||||||
if (const char * home_var = std::getenv("HOME"))
|
if (const char * home_var = std::getenv("HOME"))
|
||||||
home = home_var;
|
HANDLER(price_db_).on((path(home_var) / ".pricedb").string());
|
||||||
|
else
|
||||||
init_file = home ? *home / ".ledgerrc" : "./.ledgerrc";
|
HANDLER(price_db_).on(path("./.pricedb").string());
|
||||||
price_db = home ? *home / ".pricedb" : "./.pricedb";
|
|
||||||
|
|
||||||
register_parser(new textual_parser_t);
|
register_parser(new textual_parser_t);
|
||||||
|
|
||||||
// Add time commodity conversions, so that timelog's may be parsed
|
// Add time commodity conversions, so that timelog's may be parsed
|
||||||
// in terms of seconds, but reported as minutes or hours.
|
// 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);
|
commodity->add_flags(COMMODITY_BUILTIN | COMMODITY_NOMARKET);
|
||||||
} else {
|
else
|
||||||
assert(false);
|
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,
|
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);
|
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,
|
std::size_t session_t::read_data(journal_t& journal,
|
||||||
const string& master_account)
|
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)");
|
throw_(parse_error, "No journal file was specified (please use -f)");
|
||||||
|
|
||||||
std::size_t entry_count = 0;
|
std::size_t entry_count = 0;
|
||||||
|
|
@ -200,7 +143,7 @@ std::size_t session_t::read_data(journal_t& journal,
|
||||||
if (! master_account.empty())
|
if (! master_account.empty())
|
||||||
acct = journal.find_account(master_account);
|
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 (journal.price_db && exists(*journal.price_db)) {
|
||||||
if (read_journal(journal, *journal.price_db)) {
|
if (read_journal(journal, *journal.price_db)) {
|
||||||
throw_(parse_error, "Entries not allowed in price history file");
|
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 == "-") {
|
if (pathname == "-") {
|
||||||
journal.sources.push_back("/dev/stdin");
|
journal.sources.push_back("/dev/stdin");
|
||||||
|
|
||||||
|
|
@ -247,6 +190,20 @@ std::size_t session_t::read_data(journal_t& journal,
|
||||||
return entry_count;
|
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()
|
void session_t::clean_xacts()
|
||||||
{
|
{
|
||||||
session_xacts_iterator walker(*this);
|
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();
|
const char * p = name.c_str();
|
||||||
switch (*p) {
|
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':
|
case 'o':
|
||||||
if (std::strncmp(p, "opt_", 4) == 0) {
|
if (WANT_OPT()) { p += OPT_PREFIX_LEN;
|
||||||
p = p + 4;
|
|
||||||
switch (*p) {
|
switch (*p) {
|
||||||
|
case 'a':
|
||||||
|
OPT(abbrev_len_);
|
||||||
|
else OPT_(account_); // -a
|
||||||
|
break;
|
||||||
case 'd':
|
case 'd':
|
||||||
if (std::strcmp(p, "debug_") == 0)
|
OPT(download); // -Q
|
||||||
return MAKE_FUNCTOR(session_t::option_debug_);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'f':
|
case 'f':
|
||||||
if ((*(p + 1) == '_' && ! *(p + 2)) ||
|
OPT_(file_); // -f
|
||||||
std::strcmp(p, "file_") == 0)
|
|
||||||
return MAKE_FUNCTOR(session_t::option_file_);
|
|
||||||
break;
|
break;
|
||||||
|
case 'i':
|
||||||
case 't':
|
OPT(input_date_format_);
|
||||||
if (std::strcmp(p, "trace_") == 0)
|
|
||||||
return MAKE_FUNCTOR(session_t::option_trace_);
|
|
||||||
break;
|
break;
|
||||||
|
case 'p':
|
||||||
case 'v':
|
OPT(price_db_);
|
||||||
if (! *(p + 1) || std::strcmp(p, "verbose") == 0)
|
break;
|
||||||
return MAKE_FUNCTOR(session_t::option_verbose);
|
case 'Q':
|
||||||
else if (std::strcmp(p, "version") == 0)
|
OPT_CH(download); // -Q
|
||||||
return MAKE_FUNCTOR(session_t::option_version);
|
|
||||||
else if (std::strcmp(p, "verify") == 0)
|
|
||||||
return MAKE_FUNCTOR(session_t::option_verify);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return expr_t::ptr_op_t();
|
return expr_t::ptr_op_t();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
150
src/session.h
150
src/session.h
|
|
@ -64,66 +64,25 @@ class session_t : public noncopyable, public scope_t
|
||||||
friend void set_session_context(session_t * session);
|
friend void set_session_context(session_t * session);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
std::list<path> data_files;
|
bool flush_on_next_data_file;
|
||||||
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;
|
int current_year;
|
||||||
|
|
||||||
bool download_quotes;
|
|
||||||
|
|
||||||
format_t::elision_style_t elision_style;
|
|
||||||
int abbrev_length;
|
|
||||||
|
|
||||||
bool ansi_codes;
|
|
||||||
bool ansi_invert;
|
|
||||||
|
|
||||||
shared_ptr<commodity_pool_t> commodity_pool;
|
shared_ptr<commodity_pool_t> commodity_pool;
|
||||||
ptr_list<journal_t::parser_t> parsers;
|
ptr_list<journal_t::parser_t> parsers;
|
||||||
ptr_list<journal_t> journals;
|
ptr_list<journal_t> journals;
|
||||||
scoped_ptr<account_t> master;
|
scoped_ptr<account_t> master;
|
||||||
|
|
||||||
session_t();
|
explicit session_t();
|
||||||
virtual ~session_t();
|
virtual ~session_t() {
|
||||||
|
TRACE_DTOR(session_t);
|
||||||
|
}
|
||||||
|
|
||||||
void now_at_command_line(const bool truth) {
|
void now_at_command_line(const bool truth) {
|
||||||
next_data_file_from_command_line = truth;
|
flush_on_next_data_file = true;
|
||||||
next_price_db_from_command_line = truth;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
journal_t * create_journal() {
|
journal_t * create_journal();
|
||||||
journal_t * journal = new journal_t(master.get());
|
void close_journal(journal_t * journal);
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::size_t read_journal(journal_t& journal,
|
std::size_t read_journal(journal_t& journal,
|
||||||
std::istream& in,
|
std::istream& in,
|
||||||
|
|
@ -133,102 +92,47 @@ public:
|
||||||
const path& pathname,
|
const path& pathname,
|
||||||
account_t * master = NULL);
|
account_t * master = NULL);
|
||||||
|
|
||||||
void read_init();
|
|
||||||
|
|
||||||
std::size_t read_data(journal_t& journal,
|
std::size_t read_data(journal_t& journal,
|
||||||
const string& master_account = "");
|
const string& master_account = "");
|
||||||
|
|
||||||
void register_parser(journal_t::parser_t * parser) {
|
void register_parser(journal_t::parser_t * parser) {
|
||||||
parsers.push_back(parser);
|
parsers.push_back(parser);
|
||||||
}
|
}
|
||||||
void unregister_parser(journal_t::parser_t * 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 clean_xacts();
|
void clean_xacts();
|
||||||
void clean_xacts(entry_t& entry);
|
void clean_xacts(entry_t& entry);
|
||||||
|
void clean_accounts();
|
||||||
void clean_all() {
|
void clean_all() {
|
||||||
clean_xacts();
|
clean_xacts();
|
||||||
clean_accounts();
|
clean_accounts();
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
// Scope members
|
|
||||||
//
|
|
||||||
|
|
||||||
virtual expr_t::ptr_op_t lookup(const string& name);
|
virtual expr_t::ptr_op_t lookup(const string& name);
|
||||||
|
|
||||||
//
|
/**
|
||||||
// Help options
|
* Option handlers
|
||||||
//
|
*/
|
||||||
|
|
||||||
value_t option_version(scope_t&) {
|
OPTION(session_t, abbrev_len_);
|
||||||
std::cout << "Ledger " << ledger::version << ", the command-line accounting tool";
|
OPTION(session_t, account_); // -a
|
||||||
std::cout << "\n\nCopyright (c) 2003-2009, John Wiegley. All rights reserved.\n\n\
|
OPTION(session_t, download); // -Q
|
||||||
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__
|
||||||
// Debug options
|
(session_t, file_, // -f
|
||||||
//
|
std::list<path> data_files;
|
||||||
|
CTOR(session_t, file_) {}
|
||||||
value_t option_trace_(scope_t&) {
|
DO_(args) {
|
||||||
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);
|
assert(args.size() == 1);
|
||||||
if (next_data_file_from_command_line &&
|
if (parent->flush_on_next_data_file) {
|
||||||
! saw_data_file_from_command_line) {
|
|
||||||
data_files.clear();
|
data_files.clear();
|
||||||
saw_data_file_from_command_line = true;
|
parent->flush_on_next_data_file = false;
|
||||||
}
|
}
|
||||||
data_files.push_back(args[0].as_string());
|
data_files.push_back(args[0].as_string());
|
||||||
return true;
|
});
|
||||||
}
|
|
||||||
|
OPTION(session_t, input_date_format_);
|
||||||
|
OPTION(session_t, price_db_);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
12
src/stream.h
12
src/stream.h
|
|
@ -61,7 +61,7 @@ namespace ledger {
|
||||||
* Cline's "C++ FAQ Lite". Arguably this should be three different
|
* Cline's "C++ FAQ Lite". Arguably this should be three different
|
||||||
* classes, but that introduces additional unneeded complications.
|
* classes, but that introduces additional unneeded complications.
|
||||||
*/
|
*/
|
||||||
class output_stream_t : public noncopyable
|
class output_stream_t
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
int pipe_to_pager_fd;
|
int pipe_to_pager_fd;
|
||||||
|
|
@ -80,6 +80,16 @@ public:
|
||||||
TRACE_CTOR(output_stream_t, "");
|
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
|
* Destroys an output_stream_t. This deletes the dynamically
|
||||||
* allocated ostream, if necessary. It also closes output file
|
* allocated ostream, if necessary. It also closes output file
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue