diff options
-rw-r--r-- | config.cc | 73 | ||||
-rw-r--r-- | config.h | 6 | ||||
-rw-r--r-- | main.cc | 115 | ||||
-rw-r--r-- | main.py | 108 | ||||
-rw-r--r-- | walk.cc | 77 |
5 files changed, 228 insertions, 151 deletions
@@ -284,6 +284,69 @@ void config_t::process_options(const std::string& command, nformat.reset(next_lines_format); } +void parse_ledger_data(journal_t * journal, + parser_t * text_parser, + parser_t * cache_parser) +{ + int entry_count = 0; + + if (! config.init_file.empty()) { + if (parse_journal_file(config.init_file, journal)) + throw error("Entries not allowed in initialization file"); + journal->sources.pop_front(); // remove init file + } + + if (cache_parser && config.use_cache && + ! config.cache_file.empty() && ! config.data_file.empty()) { + config.cache_dirty = true; + if (access(config.cache_file.c_str(), R_OK) != -1) { + std::ifstream stream(config.cache_file.c_str()); + if (cache_parser->test(stream)) { + entry_count += cache_parser->parse(stream, journal, NULL, + &config.data_file); + if (entry_count > 0) + config.cache_dirty = false; + } + } + } + + if (entry_count == 0 && ! config.data_file.empty()) { + account_t * account = NULL; + if (! config.account.empty()) + account = journal->find_account(config.account); + + if (config.data_file == "-") { + config.use_cache = false; + entry_count += parse_journal(std::cin, journal, account); + } else { + entry_count += parse_journal_file(config.data_file, journal, account); + } + + if (! config.price_db.empty()) + if (parse_journal_file(config.price_db, journal)) + throw error("Entries not allowed in price history file"); + } + + for (strings_list::iterator i = config.price_settings.begin(); + i != config.price_settings.end(); + i++) { + std::string conversion = "C "; + conversion += *i; + int i = conversion.find('='); + if (i != -1) { + conversion[i] = ' '; + std::istringstream stream(conversion); + text_parser->parse(stream, journal, journal->master); + } + } + + if (entry_count == 0) + throw error("Please specify ledger file using -f," + " or LEDGER_FILE environment variable."); + + VALIDATE(journal->valid()); +} + static void show_version(std::ostream& out) { out @@ -644,6 +707,14 @@ void py_add_config_option_handlers() add_other_option_handlers(config_options); } +BOOST_PYTHON_FUNCTION_OVERLOADS(parse_ledger_data_overloads, + parse_ledger_data, 2, 3) + +void py_option_help() +{ + option_help(std::cout); +} + void export_config() { class_< config_t > ("Config") @@ -691,6 +762,8 @@ void export_config() scope().attr("config") = ptr(&config); + def("option_help", py_option_help); + def("parse_ledger_data", parse_ledger_data, parse_ledger_data_overloads()); def("add_config_option_handlers", py_add_config_option_handlers); } @@ -6,6 +6,7 @@ #include "valexpr.h" #include "datetime.h" #include "format.h" +#include "parser.h" #include <iostream> #include <memory> @@ -84,6 +85,11 @@ extern std::list<option_t> config_options; void option_help(std::ostream& out); +// Parse what ledger data can be determined from the config settings +void parse_ledger_data(journal_t * journal, + parser_t * text_parser, + parser_t * cache_parser = NULL); + struct declared_option_handler : public option_handler { declared_option_handler(const std::string& label, const std::string& opt_chars) { @@ -33,9 +33,7 @@ using namespace ledger; namespace { TIMER_DEF(write_cache, "writing cache file"); TIMER_DEF(report_gen, "generation of final report"); - TIMER_DEF(parse_files, "parsing ledger files"); TIMER_DEF(process_opts, "processing args and environment"); - TIMER_DEF(read_cache, "reading cache file"); } #if !defined(DEBUG_LEVEL) || DEBUG_LEVEL <= RELEASE @@ -72,73 +70,6 @@ namespace std { #endif -void parse_ledger_data(journal_t * journal, - parser_t * text_parser, - parser_t * cache_parser) -{ - TIMER_START(parse_files); - - int entry_count = 0; - - if (! config.init_file.empty()) { - if (parse_journal_file(config.init_file, journal)) - throw error("Entries not allowed in initialization file"); - journal->sources.pop_front(); // remove init file - } - - if (config.use_cache && ! config.cache_file.empty() && - ! config.data_file.empty()) { - config.cache_dirty = true; - if (access(config.cache_file.c_str(), R_OK) != -1) { - std::ifstream stream(config.cache_file.c_str()); - if (cache_parser->test(stream)) { - entry_count += cache_parser->parse(stream, journal, NULL, - &config.data_file); - if (entry_count > 0) - config.cache_dirty = false; - } - } - } - - if (entry_count == 0 && ! config.data_file.empty()) { - account_t * account = NULL; - if (! config.account.empty()) - account = journal->find_account(config.account); - - if (config.data_file == "-") { - config.use_cache = false; - entry_count += parse_journal(std::cin, journal, account); - } else { - entry_count += parse_journal_file(config.data_file, journal, account); - } - - if (! config.price_db.empty()) - if (parse_journal_file(config.price_db, journal)) - throw error("Entries not allowed in price history file"); - } - - for (strings_list::iterator i = config.price_settings.begin(); - i != config.price_settings.end(); - i++) { - std::string conversion = "C "; - conversion += *i; - int i = conversion.find('='); - if (i != -1) { - conversion[i] = ' '; - std::istringstream stream(conversion); - text_parser->parse(stream, journal, journal->master); - } - } - - if (entry_count == 0) - throw error("Please specify ledger file using -f," - " or LEDGER_FILE environment variable."); - - VALIDATE(journal->valid()); - - TIMER_STOP(parse_files); -} - item_handler<transaction_t> * chain_formatters(const std::string& command, item_handler<transaction_t> * base_formatter, @@ -146,13 +77,11 @@ chain_formatters(const std::string& command, { item_handler<transaction_t> * formatter = NULL; + ptrs.push_back(formatter = base_formatter); + // format_transactions write each transaction received to the // output stream. - if (command == "b" || command == "E") { - ptrs.push_back(formatter = base_formatter); - } else { - ptrs.push_back(formatter = base_formatter); - + if (! (command == "b" || command == "E")) { // filter_transactions will only pass through transactions // matching the `display_predicate'. if (! config.display_predicate.empty()) @@ -260,24 +189,6 @@ int parse_and_report(int argc, char * argv[], char * envp[]) TIMER_STOP(process_opts); - // Parse initialization files, ledger data, price database, etc. - - std::auto_ptr<binary_parser_t> bin_parser(new binary_parser_t); -#ifdef READ_GNUCASH - std::auto_ptr<gnucash_parser_t> gnucash_parser(new gnucash_parser_t); -#endif - std::auto_ptr<qif_parser_t> qif_parser(new qif_parser_t); - std::auto_ptr<textual_parser_t> text_parser(new textual_parser_t); - - register_parser(bin_parser.get()); -#ifdef READ_GNUCASH - register_parser(gnucash_parser.get()); -#endif - register_parser(qif_parser.get()); - register_parser(text_parser.get()); - - parse_ledger_data(journal.get(), text_parser.get(), bin_parser.get()); - // Read the command word, canonicalize it to its one letter form, // then configure the system based on the kind of report to be // generated @@ -297,6 +208,26 @@ int parse_and_report(int argc, char * argv[], char * envp[]) else throw error(std::string("Unrecognized command '") + command + "'"); + // Parse initialization files, ledger data, price database, etc. + + std::auto_ptr<binary_parser_t> bin_parser(new binary_parser_t); +#ifdef READ_GNUCASH + std::auto_ptr<gnucash_parser_t> gnucash_parser(new gnucash_parser_t); +#endif + std::auto_ptr<qif_parser_t> qif_parser(new qif_parser_t); + std::auto_ptr<textual_parser_t> text_parser(new textual_parser_t); + + register_parser(bin_parser.get()); +#ifdef READ_GNUCASH + register_parser(gnucash_parser.get()); +#endif + register_parser(qif_parser.get()); + register_parser(text_parser.get()); + + parse_ledger_data(journal.get(), text_parser.get(), bin_parser.get()); + + // Process the command word and its following arguments + config.process_options(command, arg, args.end()); std::auto_ptr<entry_t> new_entry; @@ -4,46 +4,114 @@ import time from ledger import * -def hello (str): - print "Hello:", str -def goodbye (str): - print "Goodbye:", str +journal = Journal () add_config_option_handlers () -add_option_handler ("hello", ":", hello) -add_option_handler ("goodbye", ":", goodbye) args = process_arguments (sys.argv[1:]) +config.use_cache = len (config.data_file) > 0 process_environment (os.environ, "LEDGER_") -if len (args) > 0: - config.process_options (args[0], args[1:]) +if os.environ.has_key ("LEDGER"): + process_option ("file", os.environ["LEDGER"]) +if os.environ.has_key ("PRICE_HIST"): + process_option ("price-db", os.environ["PRICE_HIST"]) +if os.environ.has_key ("PRICE_EXP"): + process_option ("price-exp", os.environ["PRICE_EXP"]) + +if len (args) == 0: + option_help () + sys.exit (0) + +command = args.pop (0); + +if command == "balance" or command == "bal" or command == "b": + command = "b" +elif command == "register" or command == "reg" or command == "r": + command = "r" +elif command == "print" or command == "p": + command = "p" +elif command == "entry": + command = "e" +elif command == "equity": + command = "E" +else: + print "Unrecognized command:", command + sys.exit (1) text_parser = TextualParser () +bin_parser = BinaryParser () +qif_parser = QifParser () + register_parser (text_parser) +register_parser (bin_parser) +register_parser (qif_parser) -journal = Journal () -print parse_journal_file (args[0], journal), "entries" +parse_ledger_data (journal, text_parser, bin_parser) + +config.process_options(command, args); + +new_entry = None +if command == "e": + new_entry = journal.derive_entry (args) + if new_entry is None: + sys.exit (1) class FormatTransaction (TransactionHandler): - def __init__ (self, fmt): - self.formatter = Format (fmt) + last_entry = None + + def __init__ (self, fmt = None): + if fmt is None: + self.formatter = config.format + self.nformatter = config.nformat + else: + self.formatter = Format (fmt) + + self.last_entry = None + TransactionHandler.__init__ (self) def __call__ (self, xact): - print self.formatter.format(xact) + if xact.entry is self.last_entry: + print self.nformatter.format(xact), + else: + print self.formatter.format(xact), + self.last_entry = xact.entry + +handler = FormatTransaction() + +if not (command == "b" or command == "E"): + if config.display_predicate: + handler = FilterTransactions(handler, config.display_predicate) + + handler = CalcTransactions(handler, config.show_inverted) -expr = parse_value_expr ("a*2") + if config.sort_order: + handler = SortTransactions(handler, config.sort_order) -def foo(x, val): - return x.xact.amount + expr.compute (x) + val + if config.show_revalued: + handler = ChangedValueTransactions(handler, config.show_revalued_only) -handler = FormatTransaction("%D %-20P %N %('foo'{$100})") -handler = FilterTransactions (handler, "/Checking/") + if config.show_collapsed: + handler = CollapseTransactions(handler); + + if config.show_subtotal: + handler = SubtotalTransactions(handler) + elif config.report_interval: + handler = IntervalTransactions(handler, config.report_interval) + elif config.days_of_the_week: + handler = DowTransactions(handler) + +if config.show_related: + handler = RelatedTransactions(handler, config.show_all_related) + +if config.predicate: + handler = FilterTransactions(handler, config.predicate) for entry in journal: for xact in entry: handler (xact) -for date in Interval ("weekly last month"): - print time.strftime ("%c", time.localtime (date)) +handler.flush () + +# jww (2004-09-14): still need to write out the cache @@ -347,98 +347,97 @@ void py_walk_transactions(entry_t& entry, item_handler<transaction_t>& handler) void export_walk() { - class_< item_handler<transaction_t>, - item_handler_wrap<transaction_t> > ("TransactionHandler") - .def(init<item_handler<transaction_t> *>()) + typedef item_handler<transaction_t> xact_handler_t; - .def("flush", &item_handler<transaction_t>::flush, + class_< xact_handler_t, item_handler_wrap<transaction_t> > + ("TransactionHandler") + .def(init<xact_handler_t *>()) + + .def("flush", &xact_handler_t::flush, &item_handler_wrap<transaction_t>::default_flush) - .def("__call__", &item_handler<transaction_t>::operator(), + .def("__call__", &xact_handler_t::operator(), &item_handler_wrap<transaction_t>::default_call) ; - class_< ignore_transactions > ("IgnoreTransactions") - .def("flush", &item_handler<transaction_t>::flush) + class_< ignore_transactions, bases<xact_handler_t> > + ("IgnoreTransactions") + .def("flush", &xact_handler_t::flush) .def("__call__", &ignore_transactions::operator()); ; - class_< clear_transaction_data > ("ClearTransactionData") - .def("flush", &item_handler<transaction_t>::flush) + class_< clear_transaction_data, bases<xact_handler_t> > + ("ClearTransactionData") + .def("flush", &xact_handler_t::flush) .def("__call__", &clear_transaction_data::operator()); ; - class_< set_account_value > - ("SetAccountValue", init<item_handler<transaction_t> *>() + class_< set_account_value, bases<xact_handler_t> > + ("SetAccountValue", init<xact_handler_t *>() [with_custodian_and_ward<1, 2>()]) - .def("flush", &item_handler<transaction_t>::flush) + .def("flush", &xact_handler_t::flush) .def("__call__", &set_account_value::operator()); ; -#if 0 - class_< sort_transactions > - ("SortTransactions", init<item_handler<transaction_t> *>() + class_< sort_transactions, bases<xact_handler_t> > + ("SortTransactions", init<xact_handler_t *, const value_expr_t *>() [with_custodian_and_ward<1, 2>()]) .def("flush", &sort_transactions::flush) .def("__call__", &sort_transactions::operator()); ; -#endif - class_< filter_transactions > - ("FilterTransactions", init<item_handler<transaction_t> *, std::string>() + class_< filter_transactions, bases<xact_handler_t> > + ("FilterTransactions", init<xact_handler_t *, std::string>() [with_custodian_and_ward<1, 2>()]) - .def("flush", &item_handler<transaction_t>::flush) + .def("flush", &xact_handler_t::flush) .def("__call__", &filter_transactions::operator()); ; - class_< calc_transactions > - ("CalcTransactions", init<item_handler<transaction_t> *, optional<bool> >() + class_< calc_transactions, bases<xact_handler_t> > + ("CalcTransactions", init<xact_handler_t *, optional<bool> >() [with_custodian_and_ward<1, 2>()]) - .def("flush", &item_handler<transaction_t>::flush) + .def("flush", &xact_handler_t::flush) .def("__call__", &calc_transactions::operator()); ; - class_< collapse_transactions > - ("CollapseTransactions", init<item_handler<transaction_t> *>() + class_< collapse_transactions, bases<xact_handler_t> > + ("CollapseTransactions", init<xact_handler_t *>() [with_custodian_and_ward<1, 2>()]) .def("flush", &collapse_transactions::flush) .def("__call__", &collapse_transactions::operator()); ; - class_< changed_value_transactions > - ("ChangeValueTransactions", init<item_handler<transaction_t> *, bool>() + class_< changed_value_transactions, bases<xact_handler_t> > + ("ChangeValueTransactions", init<xact_handler_t *, bool>() [with_custodian_and_ward<1, 2>()]) .def("flush", &changed_value_transactions::flush) .def("__call__", &changed_value_transactions::operator()); ; - class_< subtotal_transactions > - ("SubtotalTransactions", init<item_handler<transaction_t> *>() + class_< subtotal_transactions, bases<xact_handler_t> > + ("SubtotalTransactions", init<xact_handler_t *>() [with_custodian_and_ward<1, 2>()]) .def("flush", subtotal_transactions_flush) .def("__call__", &subtotal_transactions::operator()); ; -#if 0 - class_< interval_transactions > - ("IntervalTransactions", init<item_handler<transaction_t> *>() + class_< interval_transactions, bases<xact_handler_t> > + ("IntervalTransactions", init<xact_handler_t *, interval_t>() [with_custodian_and_ward<1, 2>()]) - .def("flush", &item_handler<transaction_t>::flush) + .def("flush", &xact_handler_t::flush) .def("__call__", &interval_transactions::operator()); ; -#endif - class_< dow_transactions > - ("DowTransactions", init<item_handler<transaction_t> *>() + class_< dow_transactions, bases<xact_handler_t> > + ("DowTransactions", init<xact_handler_t *>() [with_custodian_and_ward<1, 2>()]) .def("flush", &dow_transactions::flush) .def("__call__", &dow_transactions::operator()); ; - class_< related_transactions > - ("RelatedTransactions", - init<item_handler<transaction_t> *, optional<bool> >() + class_< related_transactions, bases<xact_handler_t> > + ("RelatedTransactions", init<xact_handler_t *, optional<bool> >() [with_custodian_and_ward<1, 2>()]) - .def("flush", &item_handler<transaction_t>::flush) + .def("flush", &xact_handler_t::flush) .def("__call__", &related_transactions::operator()); ; |