diff options
author | John Wiegley <johnw@newartisans.com> | 2009-02-06 03:31:41 -0400 |
---|---|---|
committer | John Wiegley <johnw@newartisans.com> | 2009-02-06 03:31:41 -0400 |
commit | cf6babcf9048f7e9205b1bead4794d8e2e9e8d62 (patch) | |
tree | 38688d2cd2433517045a67d2ef3f2777ee335050 /src | |
parent | ecc5a1aab50d57e65b654ea9f8a84f17208ca612 (diff) | |
download | fork-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.cc | 31 | ||||
-rw-r--r-- | src/global.cc | 192 | ||||
-rw-r--r-- | src/global.h | 44 | ||||
-rw-r--r-- | src/handler.h | 29 | ||||
-rw-r--r-- | src/main.cc | 4 | ||||
-rw-r--r-- | src/option.cc | 18 | ||||
-rw-r--r-- | src/output.h | 4 | ||||
-rw-r--r-- | src/precmd.cc | 2 | ||||
-rw-r--r-- | src/report.cc | 94 | ||||
-rw-r--r-- | src/report.h | 814 | ||||
-rw-r--r-- | src/session.cc | 197 | ||||
-rw-r--r-- | src/session.h | 164 | ||||
-rw-r--r-- | src/stream.h | 12 |
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. |