diff options
author | John Wiegley <johnw@newartisans.com> | 2008-08-03 21:38:53 -0400 |
---|---|---|
committer | John Wiegley <johnw@newartisans.com> | 2008-08-03 21:38:53 -0400 |
commit | bbdab793029f156425180282e0e7a2a7090c1c4a (patch) | |
tree | 55ed87b2ed57b2da5ecf17ca0dd4ac53bd2988c4 /main.cc | |
parent | 3e4b01694070be141728d19f505926b277ac70b3 (diff) | |
download | fork-ledger-bbdab793029f156425180282e0e7a2a7090c1c4a.tar.gz fork-ledger-bbdab793029f156425180282e0e7a2a7090c1c4a.tar.bz2 fork-ledger-bbdab793029f156425180282e0e7a2a7090c1c4a.zip |
Rearranged the code a bit, breaking walk.cc into several different files:
compare compare_items<T>
handler item_handler<T>
iterators used to iterators sets of journal objects
filters derived from item_handler, they morph the result set
output derived from item_handler, these do the printing
Also, created a new 'help' files which contains just Ledger's help text.
Diffstat (limited to 'main.cc')
-rw-r--r-- | main.cc | 543 |
1 files changed, 274 insertions, 269 deletions
@@ -29,15 +29,21 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "utils.h" +#include "session.h" +#include "report.h" #include "option.h" +#include "output.h" +#include "help.h" + +#include "textual.h" +#include "qif.h" #if defined(HAVE_EXPAT) || defined(HAVE_XMLPARSE) +#include "xml.h" #include "gnucash.h" #endif -#include "qif.h" +#ifdef HAVE_LIBOFX #include "ofx.h" - -#include <ledger.h> +#endif #ifdef HAVE_UNIX_PIPES #include <sys/types.h> @@ -46,352 +52,351 @@ #endif namespace ledger { - value_t register_command(call_scope_t& args) + template <class Formatter = format_xacts> + class xacts_report { - ptr_t<report_t> report(args, 0); - ptr_t<std::ostream> ostream(args, 1); + string format_name; - report->xacts_report - (xact_handler_ptr(new format_xacts - (*ostream, report->session.register_format))); - return true; - } -} + public: + xacts_report(const string& _format_name) + : format_name(_format_name) {} -static int read_and_report(ledger::report_t& report, int argc, char * argv[], - char * envp[]) -{ - using namespace ledger; + value_t operator()(call_scope_t& args) + { + ptr_t<std::ostream> ostream(args, 0); + var_t<string> format(args, format_name); + + find_scope<report_t>(args).xacts_report + (xact_handler_ptr(new Formatter(*ostream, *format))); + return true; + } + }; - session_t& session(report.session); + template <class Formatter = format_accounts> + class accounts_report + { + string format_name; - // Handle the command-line arguments + public: + accounts_report(const string& _format_name) + : format_name(_format_name) {} - strings_list args; - process_arguments(argc - 1, argv + 1, false, report, args); + value_t operator()(call_scope_t& args) + { + ptr_t<std::ostream> ostream(args, 0); + var_t<string> format(args, format_name); - if (args.empty()) { -#if 0 - help(std::cerr); -#endif - return 1; - } - strings_list::iterator arg = args.begin(); + find_scope<report_t>(args).accounts_report + (acct_handler_ptr(new Formatter(*ostream, *format))); + return true; + } + }; - if (! session.cache_file) - session.use_cache = false; - else - session.use_cache = ! session.data_file.empty() && session.price_db; + int read_and_report(ledger::report_t& report, + int argc, char * argv[], char * envp[]) + { + using namespace ledger; - DEBUG("ledger.session.cache", "1. use_cache = " << session.use_cache); + session_t& session(report.session); - // Process the environment settings + // Handle the command-line arguments + + strings_list args; + process_arguments(argc - 1, argv + 1, false, report, args); + + if (args.empty()) { + ledger::help(std::cout); + return 1; + } + strings_list::iterator arg = args.begin(); + + if (! session.cache_file) + session.use_cache = false; + else + session.use_cache = ! session.data_file.empty() && session.price_db; - TRACE_START(environment, 1, "Processed environment variables"); - process_environment(const_cast<const char **>(envp), "LEDGER_", report); - TRACE_FINISH(environment, 1); + DEBUG("ledger.session.cache", "1. use_cache = " << session.use_cache); - optional<path> home; - if (const char * home_var = std::getenv("HOME")) - home = home_var; + // Process the environment settings - if (! session.init_file) - session.init_file = home ? *home / ".ledgerrc" : "./.ledgerrc"; - if (! session.price_db) - session.price_db = home ? *home / ".pricedb" : "./.pricedb"; + TRACE_START(environment, 1, "Processed environment variables"); + process_environment(const_cast<const char **>(envp), "LEDGER_", report); + TRACE_FINISH(environment, 1); - if (! session.cache_file) - session.cache_file = home ? *home / ".ledger-cache" : "./.ledger-cache"; + optional<path> home; + if (const char * home_var = std::getenv("HOME")) + home = home_var; - if (session.data_file == *session.cache_file) - session.use_cache = false; + if (! session.init_file) + session.init_file = home ? *home / ".ledgerrc" : "./.ledgerrc"; + if (! session.price_db) + session.price_db = home ? *home / ".pricedb" : "./.pricedb"; - DEBUG("ledger.session.cache", "2. use_cache = " << session.use_cache); + if (! session.cache_file) + session.cache_file = home ? *home / ".ledger-cache" : "./.ledger-cache"; - INFO("Initialization file is " << session.init_file->string()); - INFO("Price database is " << session.price_db->string()); - INFO("Binary cache is " << session.cache_file->string()); - INFO("Journal file is " << session.data_file.string()); + if (session.data_file == *session.cache_file) + session.use_cache = false; - if (! session.use_cache) - INFO("Binary cache mechanism will not be used"); + DEBUG("ledger.session.cache", "2. use_cache = " << session.use_cache); - // Configure the output stream + INFO("Initialization file is " << session.init_file->string()); + INFO("Price database is " << session.price_db->string()); + INFO("Binary cache is " << session.cache_file->string()); + INFO("Journal file is " << session.data_file.string()); + + if (! session.use_cache) + INFO("Binary cache mechanism will not be used"); + + // Configure the output stream #ifdef HAVE_UNIX_PIPES - int status, pfd[2]; // Pipe file descriptors + int status, pfd[2]; // Pipe file descriptors #endif - std::ostream * out = &std::cout; + std::ostream * out = &std::cout; - if (report.output_file) { - out = new ofstream(*report.output_file); - } -#ifdef HAVE_UNIX_PIPES - else if (report.pager) { - status = pipe(pfd); - if (status == -1) - throw_(std::logic_error, "Failed to create pipe"); - - status = fork(); - if (status < 0) { - throw_(std::logic_error, "Failed to fork child process"); + if (report.output_file) { + out = new ofstream(*report.output_file); } - else if (status == 0) { // child - // Duplicate pipe's reading end into stdin - status = dup2(pfd[0], STDIN_FILENO); +#ifdef HAVE_UNIX_PIPES + else if (report.pager) { + status = pipe(pfd); if (status == -1) - perror("dup2"); + throw_(std::logic_error, "Failed to create pipe"); - // Close unuseful file descriptors: the pipe's writing and - // reading ends (the latter is not needed anymore, after the - // duplication). - close(pfd[1]); - close(pfd[0]); - - // Find command name: its the substring starting right of the - // rightmost '/' character in the pager pathname. See manpage - // for strrchr. - execlp(report.pager->native_file_string().c_str(), - basename(*report.pager).c_str(), NULL); - perror("execl"); - exit(1); - } - else { // parent - close(pfd[0]); - out = new boost::fdostream(pfd[1]); + status = fork(); + if (status < 0) { + throw_(std::logic_error, "Failed to fork child process"); + } + else if (status == 0) { // child + // Duplicate pipe's reading end into stdin + status = dup2(pfd[0], STDIN_FILENO); + if (status == -1) + perror("dup2"); + + // Close unuseful file descriptors: the pipe's writing and + // reading ends (the latter is not needed anymore, after the + // duplication). + close(pfd[1]); + close(pfd[0]); + + // Find command name: its the substring starting right of the + // rightmost '/' character in the pager pathname. See manpage + // for strrchr. + execlp(report.pager->native_file_string().c_str(), + basename(*report.pager).c_str(), NULL); + perror("execl"); + exit(1); + } + else { // parent + close(pfd[0]); + out = new boost::fdostream(pfd[1]); + } } - } #endif - // Read the command word and create a command object based on it + // Read the command word and see if it's any of the debugging commands + // that Ledger supports. - string verb = *arg++; + string verb = *arg++; - if (verb == "parse") { - expr_t expr(*arg); + if (verb == "parse") { + expr_t expr(*arg); - *out << "Value expression as input: " << *arg << std::endl; + *out << "Value expression as input: " << *arg << std::endl; - *out << "Value expression as parsed: "; - expr.print(*out, report); - *out << std::endl; - - *out << std::endl; - *out << "--- Parsed tree ---" << std::endl; - expr.dump(*out); - - *out << std::endl; - *out << "--- Calculated value ---" << std::endl; - expr.calc(report).print(*out); - *out << std::endl; - - return 0; - } - else if (verb == "compile") { - expr_t expr(*arg); - - *out << "Value expression as input: " << *arg << std::endl; - *out << "Value expression as parsed: "; - expr.print(*out, report); - *out << std::endl; + *out << "Value expression as parsed: "; + expr.print(*out, report); + *out << std::endl; - *out << std::endl; - *out << "--- Parsed tree ---" << std::endl; - expr.dump(*out); + *out << std::endl; + *out << "--- Parsed tree ---" << std::endl; + expr.dump(*out); - expr.compile(report); + *out << std::endl; + *out << "--- Calculated value ---" << std::endl; + expr.calc(report).print(*out); + *out << std::endl; - *out << std::endl; - *out << "--- Compiled tree ---" << std::endl; - expr.dump(*out); + return 0; + } + else if (verb == "compile") { + expr_t expr(*arg); - *out << std::endl; - *out << "--- Calculated value ---" << std::endl; - expr.calc(report).print(*out); - *out << std::endl; + *out << "Value expression as input: " << *arg << std::endl; + *out << "Value expression as parsed: "; + expr.print(*out, report); + *out << std::endl; - return 0; - } - else if (verb == "eval") { - expr_t expr(*arg); - *out << expr.calc(report).strip_annotations() << std::endl; - return 0; - } - else if (verb == "format") { - format_t fmt(*arg); - fmt.dump(*out); - return 0; - } - else if (verb == "period") { - interval_t interval(*arg); - - if (! is_valid(interval.begin)) { - *out << "Time period has no beginning." << std::endl; - } else { - *out << "begin: " << format_date(interval.begin) << std::endl; - *out << " end: " << format_date(interval.end) << std::endl; *out << std::endl; + *out << "--- Parsed tree ---" << std::endl; + expr.dump(*out); - date_t date = interval.first(); + expr.compile(report); - for (int i = 0; i < 20; i++) { - *out << std::right; - out->width(2); + *out << std::endl; + *out << "--- Compiled tree ---" << std::endl; + expr.dump(*out); - *out << i << ": " << format_date(date) << std::endl; + *out << std::endl; + *out << "--- Calculated value ---" << std::endl; + expr.calc(report).print(*out); + *out << std::endl; - date = interval.increment(date); - if (is_valid(interval.end) && date >= interval.end) - break; - } + return 0; } - return 0; - } + else if (verb == "eval") { + expr_t expr(*arg); + *out << expr.calc(report).strip_annotations() << std::endl; + return 0; + } + else if (verb == "format") { + format_t fmt(*arg); + fmt.dump(*out); + return 0; + } + else if (verb == "period") { + interval_t interval(*arg); - // Parse the initialization file, which can only be textual; then - // parse the journal data. + if (! is_valid(interval.begin)) { + *out << "Time period has no beginning." << std::endl; + } else { + *out << "begin: " << format_date(interval.begin) << std::endl; + *out << " end: " << format_date(interval.end) << std::endl; + *out << std::endl; - session.read_init(); + date_t date = interval.first(); - INFO_START(journal, "Read journal file"); + for (int i = 0; i < 20; i++) { + *out << std::right; + out->width(2); - journal_t& journal(*session.create_journal()); + *out << i << ": " << format_date(date) << std::endl; - std::size_t count = session.read_data(journal, report.account); - if (count == 0) - throw_(parse_error, "Failed to locate any journal entries; " - "did you specify a valid file with -f?"); + date = interval.increment(date); + if (is_valid(interval.end) && date >= interval.end) + break; + } + } + return 0; + } - INFO_FINISH(journal); + // Parse the initialization file, which can only be textual; then + // parse the journal data. - INFO("Found " << count << " entries"); + session.read_init(); - TRACE_FINISH(entry_text, 1); - TRACE_FINISH(entry_date, 1); - TRACE_FINISH(entry_details, 1); - TRACE_FINISH(entry_xacts, 1); - TRACE_FINISH(entries, 1); - TRACE_FINISH(parsing_total, 1); + INFO_START(journal, "Read journal file"); - // Are we handling the expr commands? Do so now. + journal_t& journal(*session.create_journal()); - if (verb == "expr") { - expr_t expr(*arg); + std::size_t count = session.read_data(journal, report.account); + if (count == 0) + throw_(parse_error, "Failed to locate any journal entries; " + "did you specify a valid file with -f?"); - IF_INFO() { - *out << "Value expression tree:" << std::endl; - expr.dump(*out); - *out << std::endl; - *out << "Value expression parsed was:" << std::endl; - expr.print(*out, report); - *out << std::endl << std::endl; - *out << "Result of calculation: "; - } + INFO_FINISH(journal); - *out << expr.calc(report).strip_annotations() << std::endl; + INFO("Found " << count << " entries"); - return 0; - } + TRACE_FINISH(entry_text, 1); + TRACE_FINISH(entry_date, 1); + TRACE_FINISH(entry_details, 1); + TRACE_FINISH(entry_xacts, 1); + TRACE_FINISH(entries, 1); + TRACE_FINISH(parsing_total, 1); - // Read the command word and create a command object based on it + // Create a command object based on the command verb that was seen + // above. - function_t command; + function_t command; - if (verb == "register" || verb == "reg" || verb == "r") - command = register_command; + if (verb == "register" || verb == "reg" || verb == "r") + command = xacts_report<>("register_format"); + else if (verb == "print" || verb == "p") + command = xacts_report<>("print_format"); + else if (verb == "balance" || verb == "bal" || verb == "b") + command = accounts_report<>("balance_format"); + else if (verb == "equity") + command = accounts_report<format_equity>("print_format"); #if 0 - else if (verb == "balance" || verb == "bal" || verb == "b") - command = balance_command(); - else if (verb == "print" || verb == "p") - command = print_command(); - else if (verb == "equity") - command = equity_command(); - else if (verb == "entry") - command = entry_command(); - else if (verb == "dump") - command = dump_command(); - else if (verb == "output") - command = output_command(); - else if (verb == "prices") - command = prices_command(); - else if (verb == "pricesdb") - command = pricesdb_command(); - else if (verb == "csv") - command = csv_command(); - else if (verb == "emacs" || verb == "lisp") - command = emacs_command(); - else if (verb == "xml") - command = xml_command(); + else if (verb == "entry") + command = entry_command(); + else if (verb == "dump") + command = dump_command(); + else if (verb == "output") + command = output_command(); + else if (verb == "prices") + command = prices_command(); + else if (verb == "pricesdb") + command = pricesdb_command(); + else if (verb == "csv") + command = csv_command(); + else if (verb == "emacs" || verb == "lisp") + command = emacs_command(); + else if (verb == "xml") + command = xml_command(); #endif - else if (verb == "expr") - ; - else if (verb == "xpath") - ; - else { - char buf[128]; - std::strcpy(buf, "command_"); - std::strcat(buf, verb.c_str()); - - if (expr_t::ptr_op_t def = report.lookup(buf)) - command = def->as_function(); - - if (! command) - throw_(std::logic_error, string("Unrecognized command '") + verb + "'"); - } + else { + char buf[128]; + std::strcpy(buf, "cmd_"); + std::strcat(buf, verb.c_str()); - // Create an argument scope containing the report command's - // arguments, and then invoke the command. + if (expr_t::ptr_op_t def = report.lookup(buf)) + command = def->as_function(); - call_scope_t command_args(report); + if (! command) + throw_(std::logic_error, string("Unrecognized command '") + verb + "'"); + } - command_args.push_back(value_t(&report)); - command_args.push_back(value_t(out)); + // Create an argument scope containing the report command's + // arguments, and then invoke the command. - for (strings_list::iterator i = arg; i != args.end(); i++) - command_args.push_back(string_value(*i)); + call_scope_t command_args(report); - INFO_START(command, "Did user command '" << verb << "'"); + command_args.push_back(value_t(out)); - command(command_args); + for (strings_list::iterator i = arg; i != args.end(); i++) + command_args.push_back(string_value(*i)); - INFO_FINISH(command); + INFO_START(command, "Did user command '" << verb << "'"); - // Clean up memory, if it matters + command(command_args); - if (DO_VERIFY() && report.output_file) - checked_delete(out); + INFO_FINISH(command); #if 0 - // Write out the binary cache, if need be + // Write out the binary cache, if need be - if (session.use_cache && session.cache_dirty && session.cache_file) { - TRACE_START(binary_cache, 1, "Wrote binary journal file"); + if (session.use_cache && session.cache_dirty && session.cache_file) { + TRACE_START(binary_cache, 1, "Wrote binary journal file"); - ofstream stream(*session.cache_file); - journal.write(stream); + ofstream stream(*session.cache_file); + journal.write(stream); - TRACE_FINISH(binary_cache, 1); - } + TRACE_FINISH(binary_cache, 1); + } #endif - // If the user specified a pager, wait for it to exit now + // If the user specified a pager, wait for it to exit now #ifdef HAVE_UNIX_PIPES - if (! report.output_file && report.pager) { - checked_delete(out); - close(pfd[1]); - - // Wait for child to finish - wait(&status); - if (status & 0xffff != 0) - throw_(std::logic_error, "Something went wrong in the pager"); - } + if (! report.output_file && report.pager) { + checked_delete(out); + close(pfd[1]); + + // Wait for child to finish + wait(&status); + if (status & 0xffff != 0) + throw_(std::logic_error, "Something went wrong in the pager"); + } #endif - else if (DO_VERIFY() && report.output_file) { - checked_delete(out); - } + else if (DO_VERIFY() && report.output_file) { + checked_delete(out); + } - return 0; + return 0; + } } int main(int argc, char * argv[], char * envp[]) @@ -469,7 +474,7 @@ int main(int argc, char * argv[], char * envp[]) if (DO_VERIFY()) ledger::set_session_context(); else - session.release(); // don't free anything! + session.release(); // don't free anything! just let it leak } catch (const std::exception& err) { std::cout.flush(); |