main.py now implements nearly all the functionality of main.cc

This commit is contained in:
John Wiegley 2004-09-14 17:34:48 -04:00
parent f2162bf7ee
commit 0c890de44b
5 changed files with 229 additions and 152 deletions

View file

@ -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);
}

View file

@ -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) {

115
main.cc
View file

@ -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;

110
main.py
View file

@ -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 ()
register_parser (text_parser)
bin_parser = BinaryParser ()
qif_parser = QifParser ()
journal = Journal ()
print parse_journal_file (args[0], journal), "entries"
register_parser (text_parser)
register_parser (bin_parser)
register_parser (qif_parser)
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
expr = parse_value_expr ("a*2")
handler = FormatTransaction()
def foo(x, val):
return x.xact.amount + expr.compute (x) + val
if not (command == "b" or command == "E"):
if config.display_predicate:
handler = FilterTransactions(handler, config.display_predicate)
handler = FormatTransaction("%D %-20P %N %('foo'{$100})")
handler = FilterTransactions (handler, "/Checking/")
handler = CalcTransactions(handler, config.show_inverted)
if config.sort_order:
handler = SortTransactions(handler, config.sort_order)
if config.show_revalued:
handler = ChangedValueTransactions(handler, config.show_revalued_only)
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

77
walk.cc
View file

@ -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());
;