summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJohn Wiegley <johnw@newartisans.com>2009-02-06 03:31:41 -0400
committerJohn Wiegley <johnw@newartisans.com>2009-02-06 03:31:41 -0400
commitcf6babcf9048f7e9205b1bead4794d8e2e9e8d62 (patch)
tree38688d2cd2433517045a67d2ef3f2777ee335050 /src
parentecc5a1aab50d57e65b654ea9f8a84f17208ca612 (diff)
downloadfork-ledger-cf6babcf9048f7e9205b1bead4794d8e2e9e8d62.tar.gz
fork-ledger-cf6babcf9048f7e9205b1bead4794d8e2e9e8d62.tar.bz2
fork-ledger-cf6babcf9048f7e9205b1bead4794d8e2e9e8d62.zip
Restored all the option handlers from 2.6.2, but not the options themselves.
Diffstat (limited to 'src')
-rw-r--r--src/chain.cc31
-rw-r--r--src/global.cc192
-rw-r--r--src/global.h44
-rw-r--r--src/handler.h29
-rw-r--r--src/main.cc4
-rw-r--r--src/option.cc18
-rw-r--r--src/output.h4
-rw-r--r--src/precmd.cc2
-rw-r--r--src/report.cc94
-rw-r--r--src/report.h814
-rw-r--r--src/session.cc197
-rw-r--r--src/session.h164
-rw-r--r--src/stream.h12
13 files changed, 511 insertions, 1094 deletions
diff --git a/src/chain.cc b/src/chain.cc
index 4956a237..b83c6c8c 100644
--- a/src/chain.cc
+++ b/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
// `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
diff --git a/src/global.cc b/src/global.cc
index 915713bc..36614c14 100644
--- a/src/global.cc
+++ b/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
// 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,69 +280,30 @@ expr_t::ptr_op_t global_scope_t::lookup(const string& name)
return expr_t::ptr_op_t();
}
-void handle_debug_options(int argc, char * argv[])
-{
- for (int i = 1; i < argc; i++) {
- if (argv[i][0] == '-') {
- if (std::strcmp(argv[i], "--verify") == 0) {
-#if defined(VERIFY_ON)
- verify_enabled = true; // global in utils.h
-#endif
- }
- else if (std::strcmp(argv[i], "--verbose") == 0 ||
- std::strcmp(argv[i], "-v") == 0) {
-#if defined(LOGGING_ON)
- _log_level = LOG_INFO; // global in utils.h
-#endif
- }
- else if (i + 1 < argc && std::strcmp(argv[i], "--debug") == 0) {
-#if defined(DEBUG_ON)
- _log_level = LOG_DEBUG; // global in utils.h
- _log_category = argv[i + 1]; // global in utils.h
- i++;
-#endif
- }
- else if (i + 1 < argc && std::strcmp(argv[i], "--trace") == 0) {
-#if defined(TRACING_ON)
- _log_level = LOG_TRACE; // global in utils.h
- try {
- // global in utils.h
- _trace_level = boost::lexical_cast<int>(argv[i + 1]);
- }
- catch (const boost::bad_lexical_cast& e) {
- throw std::logic_error("Argument to --trace must be an integer");
- }
- i++;
-#endif
- }
- }
- }
-}
-
-void read_environment_settings(report_t& report, char * envp[])
+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);
+ 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");
+ process_option("file", report(), p, "LEDGER");
if (const char * p = std::getenv("LEDGER_INIT"))
- process_option("init-file", report, p, "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");
+ process_option("price-db", report(), p, "PRICE_HIST");
if (const char * p = std::getenv("PRICE_EXP"))
- process_option("price-exp", report, p, "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)
+strings_list
+global_scope_t::read_command_arguments(scope_t& scope, strings_list args)
{
TRACE_START(arguments, 1, "Processed command-line arguments");
@@ -327,16 +314,17 @@ strings_list read_command_arguments(scope_t& scope, strings_list args)
return remaining;
}
-void normalize_session_options(session_t& session)
+void global_scope_t::normalize_session_options()
{
- INFO("Initialization file is " << session.init_file->string());
- INFO("Price database is " << session.price_db->string());
+ INFO("Initialization file is " << HANDLER(init_file_).str());
+ INFO("Price database is " << session().HANDLER(price_db_).str());
- foreach (const path& pathname, session.data_files)
+ foreach (const path& pathname, session().HANDLER(file_).data_files)
INFO("Journal file is " << pathname.string());
}
-function_t look_for_precommand(scope_t& scope, const string& verb)
+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();
@@ -344,7 +332,8 @@ function_t look_for_precommand(scope_t& scope, const string& verb)
return function_t();
}
-function_t look_for_command(scope_t& scope, const string& verb)
+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();
@@ -352,55 +341,94 @@ function_t look_for_command(scope_t& scope, const string& verb)
return function_t();
}
-void normalize_report_options(report_t& report, const string& verb)
+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") {
- report.HANDLER(related).on();
- report.HANDLER(related_all).on();
+ rep.HANDLER(related).on();
+ rep.HANDLER(related_all).on();
}
else if (verb == "equity") {
- report.HANDLER(subtotal).on();
+ rep.HANDLER(subtotal).on();
}
- else if (report.HANDLED(related)) {
+ else if (rep.HANDLED(related)) {
if (verb[0] == 'r') {
- report.HANDLER(invert).on();
+ rep.HANDLER(invert).on();
} else {
- report.HANDLER(subtotal).on();
- report.HANDLER(related_all).on();
+ rep.HANDLER(subtotal).on();
+ rep.HANDLER(related_all).on();
}
}
if (verb[0] != 'b' && verb[0] != 'r')
- report.what_to_keep.keep_base = true;
+ rep.HANDLER(base).on();
// Setup the default value for the display predicate
- if (report.display_predicate.empty()) {
+ if (! rep.HANDLED(display_)) {
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";
- }
+ if (! rep.HANDLED(empty))
+ rep.append_display_predicate("total");
+ if (! rep.HANDLED(subtotal))
+ rep.append_display_predicate("depth<=1");
}
else if (verb == "equity") {
- report.display_predicate = "amount_expr"; // jww (2008-08-14): ???
+ // jww (2008-08-14): ???
+ rep.append_display_predicate("amount_expr");
}
- else if (verb[0] == 'r' && ! report.HANDLED(empty)) {
- report.display_predicate = "amount";
+ else if (verb[0] == 'r' && ! rep.HANDLED(empty)) {
+ rep.append_display_predicate("amount");
}
}
- if (! report.report_period.empty() && ! report.HANDLED(sort_all_))
- report.HANDLER(sort_entries_).on();
+ 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++) {
+ if (argv[i][0] == '-') {
+ if (std::strcmp(argv[i], "--verify") == 0) {
+#if defined(VERIFY_ON)
+ verify_enabled = true; // global in utils.h
+#endif
+ }
+ else if (std::strcmp(argv[i], "--verbose") == 0 ||
+ std::strcmp(argv[i], "-v") == 0) {
+#if defined(LOGGING_ON)
+ _log_level = LOG_INFO; // global in utils.h
+#endif
+ }
+ else if (i + 1 < argc && std::strcmp(argv[i], "--debug") == 0) {
+#if defined(DEBUG_ON)
+ _log_level = LOG_DEBUG; // global in utils.h
+ _log_category = argv[i + 1]; // global in utils.h
+ i++;
+#endif
+ }
+ else if (i + 1 < argc && std::strcmp(argv[i], "--trace") == 0) {
+#if defined(TRACING_ON)
+ _log_level = LOG_TRACE; // global in utils.h
+ try {
+ // global in utils.h
+ _trace_level = boost::lexical_cast<int>(argv[i + 1]);
+ }
+ catch (const boost::bad_lexical_cast& e) {
+ throw std::logic_error("Argument to --trace must be an integer");
+ }
+ i++;
+#endif
+ }
+ }
+ }
}
} // namespace ledger
diff --git a/src/global.h b/src/global.h
index 9b9805a6..230fcb51 100644
--- a/src/global.h
+++ b/src/global.h
@@ -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
diff --git a/src/handler.h b/src/handler.h
index 83d801a3..7d420ee4 100644
--- a/src/handler.h
+++ b/src/handler.h
@@ -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
diff --git a/src/main.cc b/src/main.cc
index 72d84421..3b985ec6 100644
--- a/src/main.cc
+++ b/src/main.cc
@@ -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();
diff --git a/src/option.cc b/src/option.cc
index 7f8bdeb4..366c9c54 100644
--- a/src/option.cc
+++ b/src/option.cc
@@ -47,15 +47,15 @@ namespace {
else
*p++ = ch;
}
+ *p++ = '_';
*p = '\0';
if (expr_t::ptr_op_t op = scope.lookup(buf))
- return op_bool_tuple(op, false);
+ return op_bool_tuple(op, true);
- *p++ = '_';
- *p = '\0';
+ *--p = '\0';
- return op_bool_tuple(scope.lookup(buf), true);
+ 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';
+ buf[5] = '_';
+ buf[6] = '\0';
if (expr_t::ptr_op_t op = scope.lookup(buf))
- return op_bool_tuple(op, false);
+ return op_bool_tuple(op, true);
- buf[5] = '_';
- buf[6] = '\0';
+ buf[5] = '\0';
- return op_bool_tuple(scope.lookup(buf), true);
+ return op_bool_tuple(scope.lookup(buf), false);
}
void process_option(const function_t& opt, scope_t& scope,
diff --git a/src/output.h b/src/output.h
index d3dd6560..fd462040 100644
--- a/src/output.h
+++ b/src/output.h
@@ -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);
}
diff --git a/src/precmd.cc b/src/precmd.cc
index fd6a2457..001416a6 100644
--- a/src/precmd.cc
+++ b/src/precmd.cc
@@ -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;
}
diff --git a/src/report.cc b/src/report.cc
index 06173550..348f75bd 100644
--- a/src/report.cc
+++ b/src/report.cc
@@ -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;
diff --git a/src/report.h b/src/report.h
index b014d2c7..bc42f86c 100644
--- a/src/report.h
+++ b/src/report.h
@@ -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
+ OPTION(report_t, subtotal); // -s
+ OPTION(report_t, tail_);
- //
- // Scope members
- //
+ OPTION__
+ (report_t, total_, // -T
+ expr_t expr;
+ CTOR(report_t, total_) {
+ expr = "total";
+ });
- virtual expr_t::ptr_op_t lookup(const string& name);
+ 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
diff --git a/src/session.cc b/src/session.cc
index 423c5e0d..ed24fc23 100644
--- a/src/session.cc
+++ b/src/session.cc
@@ -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),
-
- 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),
+ : flush_on_next_data_file(false),
- ansi_codes(false),
- ansi_invert(false),
+ current_year(CURRENT_DATE().year()),
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()
+{
+ journal_t * journal = new journal_t(master.get());
+ journals.push_back(journal);
+ return journal;
+}
+
+void session_t::close_journal(journal_t * journal)
{
- TRACE_DTOR(session_t);
+ 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();
}
diff --git a/src/session.h b/src/session.h
index c66d8b26..ae0d213c 100644
--- a/src/session.h
+++ b/src/session.h
@@ -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
- //
-
- 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;
- }
-
- //
- // Debug options
- //
-
- 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 handlers
+ */
+
+ OPTION(session_t, abbrev_len_);
+ OPTION(session_t, account_); // -a
+ OPTION(session_t, download); // -Q
+
+ 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());
+ });
+
+ OPTION(session_t, input_date_format_);
+ OPTION(session_t, price_db_);
};
/**
diff --git a/src/stream.h b/src/stream.h
index 919c801d..ddc5369a 100644
--- a/src/stream.h
+++ b/src/stream.h
@@ -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;
@@ -81,6 +81,16 @@ public:
}
/**
+ * 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
* descriptor, if necessary.