Inspired by Omari Norman, I've rewritten main.cc so it's easy to approach.
This commit is contained in:
parent
75daee6a5d
commit
9d267fa133
12 changed files with 555 additions and 375 deletions
|
|
@ -151,6 +151,7 @@ pkginclude_HEADERS = \
|
||||||
src/reconcile.h \
|
src/reconcile.h \
|
||||||
src/quotes.h \
|
src/quotes.h \
|
||||||
\
|
\
|
||||||
|
src/work.h \
|
||||||
src/ledger.h \
|
src/ledger.h \
|
||||||
\
|
\
|
||||||
python/pyledger.h \
|
python/pyledger.h \
|
||||||
|
|
@ -194,7 +195,7 @@ ledger_CPPFLAGS = $(lib_cppflags)
|
||||||
if HAVE_BOOST_PYTHON
|
if HAVE_BOOST_PYTHON
|
||||||
ledger_CPPFLAGS += -I$(srcdir)/python
|
ledger_CPPFLAGS += -I$(srcdir)/python
|
||||||
endif
|
endif
|
||||||
ledger_SOURCES = src/main.cc
|
ledger_SOURCES = src/main.cc src/work.cc
|
||||||
ledger_LDADD = $(LIBOBJS) $(lib_LTLIBRARIES)
|
ledger_LDADD = $(LIBOBJS) $(lib_LTLIBRARIES)
|
||||||
if HAVE_BOOST_PYTHON
|
if HAVE_BOOST_PYTHON
|
||||||
ledger_LDADD += libledger_python.la
|
ledger_LDADD += libledger_python.la
|
||||||
|
|
|
||||||
|
|
@ -197,7 +197,7 @@ expr_t::ptr_op_t account_t::lookup(const string& name)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return session_t::current->current_report->lookup(name);
|
return session_t::current->report->lookup(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool account_t::valid() const
|
bool account_t::valid() const
|
||||||
|
|
@ -240,7 +240,7 @@ void account_t::calculate_sums()
|
||||||
}
|
}
|
||||||
|
|
||||||
call_scope_t args(*this);
|
call_scope_t args(*this);
|
||||||
value_t amount(session_t::current->current_report->get_amount_expr(args));
|
value_t amount(session_t::current->report->get_amount_expr(args));
|
||||||
if (! amount.is_null()) {
|
if (! amount.is_null()) {
|
||||||
add_or_set_value(xd.total, amount);
|
add_or_set_value(xd.total, amount);
|
||||||
xd.total_count += xd.count;
|
xd.total_count += xd.count;
|
||||||
|
|
|
||||||
|
|
@ -128,7 +128,7 @@ expr_t::ptr_op_t item_t::lookup(const string& name)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return session_t::current->current_report->lookup(name);
|
return session_t::current->report->lookup(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool item_t::valid() const
|
bool item_t::valid() const
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,7 @@
|
||||||
#define _LEDGER_H
|
#define _LEDGER_H
|
||||||
|
|
||||||
#include <utils.h>
|
#include <utils.h>
|
||||||
|
#include <option.h>
|
||||||
|
|
||||||
#include <value.h>
|
#include <value.h>
|
||||||
|
|
||||||
|
|
@ -67,4 +68,11 @@
|
||||||
#include <reconcile.h>
|
#include <reconcile.h>
|
||||||
#include <quotes.h>
|
#include <quotes.h>
|
||||||
|
|
||||||
|
#if defined(HAVE_BOOST_PYTHON)
|
||||||
|
#include <pyinterp.h>
|
||||||
|
#define LEDGER_SESSION_T python_interpreter_t
|
||||||
|
#else
|
||||||
|
#define LEDGER_SESSION_T session_t
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif // _LEDGER_H
|
#endif // _LEDGER_H
|
||||||
|
|
|
||||||
396
src/main.cc
396
src/main.cc
|
|
@ -29,335 +29,129 @@
|
||||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "session.h"
|
#include <ledger.h>
|
||||||
#include "report.h"
|
|
||||||
#include "option.h"
|
|
||||||
#include "help.h"
|
|
||||||
#include "pyinterp.h"
|
|
||||||
|
|
||||||
#include "textual.h"
|
#include "work.h" // this is where the top-level code is
|
||||||
#include "qif.h"
|
|
||||||
#include "xml.h"
|
|
||||||
#include "gnucash.h"
|
|
||||||
#ifdef HAVE_LIBOFX
|
|
||||||
#include "ofx.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace ledger {
|
|
||||||
int read_and_report(ledger::report_t& report,
|
|
||||||
int argc, char * argv[], char * envp[])
|
|
||||||
{
|
|
||||||
using namespace ledger;
|
|
||||||
|
|
||||||
session_t& session(report.session);
|
|
||||||
|
|
||||||
// Setup global defaults
|
|
||||||
|
|
||||||
optional<path> home;
|
|
||||||
if (const char * home_var = std::getenv("HOME"))
|
|
||||||
home = home_var;
|
|
||||||
|
|
||||||
session.init_file = home ? *home / ".ledgerrc" : "./.ledgerrc";
|
|
||||||
session.price_db = home ? *home / ".pricedb" : "./.pricedb";
|
|
||||||
session.cache_file = home ? *home / ".ledger-cache" : "./.ledger-cache";
|
|
||||||
|
|
||||||
// Process the environment settings
|
|
||||||
|
|
||||||
TRACE_START(environment, 1, "Processed environment variables");
|
|
||||||
|
|
||||||
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);
|
|
||||||
if (const char * p = std::getenv("LEDGER_INIT"))
|
|
||||||
process_option("init-file", report, p);
|
|
||||||
if (const char * p = std::getenv("PRICE_HIST"))
|
|
||||||
process_option("price-db", report, p);
|
|
||||||
if (const char * p = std::getenv("PRICE_EXP"))
|
|
||||||
process_option("price-exp", report, p);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
TRACE_FINISH(environment, 1);
|
|
||||||
|
|
||||||
// Read the initialization file
|
|
||||||
|
|
||||||
TRACE_START(init, 1, "Read initialization file");
|
|
||||||
|
|
||||||
session.read_init();
|
|
||||||
|
|
||||||
TRACE_FINISH(init, 1);
|
|
||||||
|
|
||||||
// Handle the command-line arguments
|
|
||||||
|
|
||||||
TRACE_START(arguments, 1, "Processed command-line arguments");
|
|
||||||
|
|
||||||
strings_list args;
|
|
||||||
process_arguments(argc - 1, argv + 1, 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 if (session.use_cache)
|
|
||||||
session.use_cache = ! session.data_file.empty() && session.price_db;
|
|
||||||
|
|
||||||
DEBUG("ledger.session.cache", "1. use_cache = " << session.use_cache);
|
|
||||||
|
|
||||||
if (session.data_file == *session.cache_file)
|
|
||||||
session.use_cache = false;
|
|
||||||
|
|
||||||
DEBUG("ledger.session.cache", "2. use_cache = " << session.use_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.use_cache)
|
|
||||||
INFO("Binary cache mechanism will not be used");
|
|
||||||
|
|
||||||
TRACE_FINISH(arguments, 1);
|
|
||||||
|
|
||||||
// Read the command word and see if it's any of the debugging commands
|
|
||||||
// that Ledger supports.
|
|
||||||
|
|
||||||
string verb = *arg++;
|
|
||||||
|
|
||||||
function_t command;
|
|
||||||
if (expr_t::ptr_op_t def = report.lookup(string("ledger_precmd_") + verb))
|
|
||||||
command = def->as_function();
|
|
||||||
|
|
||||||
// Parse the initialization file, which can only be textual; then
|
|
||||||
// parse the journal data. But only do this if there was no
|
|
||||||
// "pre-command", which are always executed without doing any
|
|
||||||
// parsing.
|
|
||||||
|
|
||||||
if (! command) {
|
|
||||||
INFO_START(journal, "Read journal file");
|
|
||||||
|
|
||||||
journal_t& journal(*session.create_journal());
|
|
||||||
|
|
||||||
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?");
|
|
||||||
|
|
||||||
INFO_FINISH(journal);
|
|
||||||
|
|
||||||
INFO("Found " << count << " entries");
|
|
||||||
|
|
||||||
TRACE_FINISH(entry_text, 1);
|
|
||||||
TRACE_FINISH(entry_details, 1);
|
|
||||||
TRACE_FINISH(entry_xacts, 1);
|
|
||||||
TRACE_FINISH(entries, 1);
|
|
||||||
TRACE_FINISH(session_parser, 1);
|
|
||||||
TRACE_FINISH(parsing_total, 1);
|
|
||||||
|
|
||||||
// Lookup the command object corresponding to the command verb.
|
|
||||||
|
|
||||||
if (expr_t::ptr_op_t def = report.lookup(string("ledger_cmd_") + verb))
|
|
||||||
command = def->as_function();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (! command)
|
|
||||||
throw_(std::logic_error, string("Unrecognized command '") + verb + "'");
|
|
||||||
|
|
||||||
#if 1
|
|
||||||
// Patch up some of the reporting options based on what kind of
|
|
||||||
// command it was.
|
|
||||||
|
|
||||||
// jww (2008-08-14): This code really needs to be rationalized away
|
|
||||||
// for 3.0.
|
|
||||||
|
|
||||||
if (verb == "print" || verb == "entry" || verb == "dump") {
|
|
||||||
report.show_related = true;
|
|
||||||
report.show_all_related = true;
|
|
||||||
}
|
|
||||||
else if (verb == "equity") {
|
|
||||||
report.show_subtotal = true;
|
|
||||||
}
|
|
||||||
else if (report.show_related) {
|
|
||||||
if (verb[0] == 'r') {
|
|
||||||
report.show_inverted = true;
|
|
||||||
} else {
|
|
||||||
report.show_subtotal = true;
|
|
||||||
report.show_all_related = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (verb[0] != 'b' && verb[0] != 'r')
|
|
||||||
amount_t::keep_base = true;
|
|
||||||
|
|
||||||
// Setup the default value for the display predicate
|
|
||||||
|
|
||||||
if (report.display_predicate.empty()) {
|
|
||||||
if (verb[0] == 'b') {
|
|
||||||
if (! report.show_empty)
|
|
||||||
report.display_predicate = "total";
|
|
||||||
if (! report.show_subtotal) {
|
|
||||||
if (! report.display_predicate.empty())
|
|
||||||
report.display_predicate += "&";
|
|
||||||
report.display_predicate += "depth<=1";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (verb == "equity") {
|
|
||||||
report.display_predicate = "amount_expr"; // jww (2008-08-14): ???
|
|
||||||
}
|
|
||||||
else if (verb[0] == 'r' && ! report.show_empty) {
|
|
||||||
report.display_predicate = "amount";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Now setup the various formatting strings
|
|
||||||
|
|
||||||
// jww (2008-08-14): I hear a song, and it's sound is "HaAaaCcK"
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
if (! date_output_format.empty())
|
|
||||||
date_t::output_format = date_output_format;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
amount_t::keep_price = report.keep_price;
|
|
||||||
amount_t::keep_date = report.keep_date;
|
|
||||||
amount_t::keep_tag = report.keep_tag;
|
|
||||||
|
|
||||||
if (! report.report_period.empty() && ! report.sort_all)
|
|
||||||
report.entry_sort = true;
|
|
||||||
|
|
||||||
// Setup the output stream, which might involve invoking the pager
|
|
||||||
|
|
||||||
report.output_stream.initialize(report.output_file, report.pager_path);
|
|
||||||
|
|
||||||
// Create an argument scope containing the report command's
|
|
||||||
// arguments, and then invoke the command.
|
|
||||||
|
|
||||||
call_scope_t command_args(report);
|
|
||||||
|
|
||||||
for (strings_list::iterator i = arg; i != args.end(); i++)
|
|
||||||
command_args.push_back(string_value(*i));
|
|
||||||
|
|
||||||
INFO_START(command, "Did user command '" << verb << "'");
|
|
||||||
|
|
||||||
command(command_args);
|
|
||||||
|
|
||||||
INFO_FINISH(command);
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
// 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");
|
|
||||||
|
|
||||||
ofstream stream(*session.cache_file);
|
|
||||||
journal.write(stream);
|
|
||||||
|
|
||||||
TRACE_FINISH(binary_cache, 1);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char * argv[], char * envp[])
|
int main(int argc, char * argv[], char * envp[])
|
||||||
{
|
{
|
||||||
int status = 1;
|
using namespace ledger;
|
||||||
|
|
||||||
for (int i = 1; i < argc; i++)
|
// The very first thing we do is handle some very special command-line
|
||||||
if (argv[i][0] == '-') {
|
// options, since they affect how the whole environment is setup:
|
||||||
if (std::strcmp(argv[i], "--verify") == 0) {
|
//
|
||||||
#if defined(VERIFY_ON)
|
// --verify ; turns on memory tracing
|
||||||
ledger::verify_enabled = true;
|
// --verbose ; turns on logging
|
||||||
#endif
|
// --debug CATEGORY ; turns on debug logging
|
||||||
}
|
// --trace LEVEL ; turns on trace logging
|
||||||
else if (std::strcmp(argv[i], "--verbose") == 0 ||
|
handle_debug_options(argc, argv);
|
||||||
std::strcmp(argv[i], "-v") == 0) {
|
|
||||||
#if defined(LOGGING_ON)
|
|
||||||
ledger::_log_level = ledger::LOG_INFO;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
else if (i + 1 < argc && std::strcmp(argv[i], "--debug") == 0) {
|
|
||||||
#if defined(DEBUG_ON)
|
|
||||||
ledger::_log_level = ledger::LOG_DEBUG;
|
|
||||||
ledger::_log_category = argv[i + 1];
|
|
||||||
i++;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
else if (i + 1 < argc && std::strcmp(argv[i], "--trace") == 0) {
|
|
||||||
#if defined(TRACING_ON)
|
|
||||||
ledger::_log_level = ledger::LOG_TRACE;
|
|
||||||
try {
|
|
||||||
ledger::_trace_level = boost::lexical_cast<int>(argv[i + 1]);
|
|
||||||
}
|
|
||||||
catch (const boost::bad_lexical_cast& e) {
|
|
||||||
std::cerr << "Argument to --trace must be an integer."
|
|
||||||
<< std::endl;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
IF_VERIFY()
|
IF_VERIFY()
|
||||||
ledger::initialize_memory_tracing();
|
initialize_memory_tracing();
|
||||||
|
|
||||||
|
// Initialize the global C++ environment
|
||||||
|
std::ios::sync_with_stdio(false);
|
||||||
|
filesystem::path::default_name_check(filesystem::portable_posix_name);
|
||||||
|
|
||||||
|
// Initialization of Ledger can now begin. The whole series of operations
|
||||||
|
// is contained in a try block, so we can report errors in a nicer fashion.
|
||||||
|
INFO("Ledger starting");
|
||||||
|
|
||||||
|
session_t * session = NULL;
|
||||||
|
int status = 1;
|
||||||
try {
|
try {
|
||||||
std::ios::sync_with_stdio(false);
|
// Create the session object, which maintains nearly all state relating to
|
||||||
|
// this invocation of Ledger.
|
||||||
|
session = new LEDGER_SESSION_T;
|
||||||
|
set_session_context(session);
|
||||||
|
|
||||||
boost::filesystem::path::default_name_check
|
// Register all known journal parsers. The order of these is important.
|
||||||
(boost::filesystem::portable_posix_name);
|
register_journal_parsers(*session);
|
||||||
|
|
||||||
INFO("Ledger starting");
|
// Create the report object, which maintains state relating to each
|
||||||
|
// command invocation. Because we're running this from main() the
|
||||||
|
// distinction between session and report doesn't matter, but if a GUI
|
||||||
|
// were calling into Ledger, it would have one session object, with a
|
||||||
|
// separate report object for each report it generated.
|
||||||
|
session->report.reset(new report_t(*session));
|
||||||
|
report_t& report(*session->report.get());
|
||||||
|
|
||||||
#if defined(HAVE_BOOST_PYTHON)
|
// Read user option settings, first in the environment, then from the
|
||||||
std::auto_ptr<ledger::session_t> session(new ledger::python_interpreter_t);
|
// user's initialization file and then from the command-line. The first
|
||||||
#else
|
// non-option argument thereafter is the "command verb".
|
||||||
std::auto_ptr<ledger::session_t> session(new ledger::session_t);
|
read_environment_settings(report, envp);
|
||||||
#endif
|
session->read_init();
|
||||||
|
|
||||||
ledger::set_session_context(session.get());
|
// Notify the session object that all option handlers invoked beyond this
|
||||||
|
// point came from the command-line
|
||||||
|
session->now_at_command_line(true);
|
||||||
|
|
||||||
#if 0
|
strings_list args = read_command_line_arguments(report, argc, argv);
|
||||||
session->register_parser(new ledger::journal_t::binary_parser_t);
|
string_iterator arg = args.begin();
|
||||||
#endif
|
string verb = *arg++;
|
||||||
session->register_parser(new ledger::xml_parser_t);
|
|
||||||
session->register_parser(new ledger::gnucash_parser_t);
|
|
||||||
#ifdef HAVE_LIBOFX
|
|
||||||
session->register_parser(new ledger::ofx_parser_t);
|
|
||||||
#endif
|
|
||||||
session->register_parser(new ledger::qif_parser_t);
|
|
||||||
session->register_parser(new ledger::textual_parser_t);
|
|
||||||
|
|
||||||
session->current_report.reset(new ledger::report_t(*session.get()));
|
// Look for a precommand first, which is defined as any defined function
|
||||||
|
// whose name starts with "ledger_precmd_". The difference between a
|
||||||
|
// precommand and a regular command is that precommands ignore the journal
|
||||||
|
// data file completely, nor is the user's init file read.
|
||||||
|
//
|
||||||
|
// Here are some examples:
|
||||||
|
//
|
||||||
|
// parse STRING ; show how a value expression is parsed
|
||||||
|
// eval STRING ; simply evaluate a value expression
|
||||||
|
// format STRING ; show how a format string is parsed
|
||||||
|
//
|
||||||
|
// If such a command is found, create the output stream for the result and
|
||||||
|
// then invoke the command.
|
||||||
|
if (function_t command = look_for_precommand(report, verb)) {
|
||||||
|
create_output_stream(report);
|
||||||
|
invoke_command_verb(report, command, arg, args.end());
|
||||||
|
}
|
||||||
|
else if (function_t command = look_for_command(report, verb)) {
|
||||||
|
// Parse the user's journal files.
|
||||||
|
if (journal_t * journal = read_journal_files(*session)) {
|
||||||
|
normalize_report_options(report, verb); // this is a total hack
|
||||||
|
|
||||||
status = read_and_report(*session->current_report.get(), argc, argv, envp);
|
// Create the output stream (it might be a file, the console or a
|
||||||
|
// PAGER subprocess) and invoke the report command.
|
||||||
|
create_output_stream(report);
|
||||||
|
invoke_command_verb(report, command, arg, args.end());
|
||||||
|
|
||||||
if (! DO_VERIFY())
|
// Write out a binary cache of the journal data, if needed and
|
||||||
session.release(); // don't free anything! just let it leak
|
// appropriate to do so
|
||||||
|
write_binary_cache(*session, journal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw_(std::logic_error, "Unrecognized command '" << verb << "'");
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we got here, everything succeeded just fine. Ledger uses exceptions
|
||||||
|
// to notify of any error conditions, so if you're using gdb, type "catch
|
||||||
|
// throw" to find the source of any errors.
|
||||||
|
status = 0;
|
||||||
}
|
}
|
||||||
catch (const std::exception& err) {
|
catch (const std::exception& err) {
|
||||||
std::cout.flush();
|
std::cout.flush();
|
||||||
std::cerr << ledger::error_context()
|
std::cerr << error_context() << "Error: " << err.what() << std::endl;
|
||||||
<< "Error: " << err.what() << std::endl;
|
|
||||||
}
|
}
|
||||||
catch (int _status) {
|
catch (int _status) {
|
||||||
status = _status;
|
status = _status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If memory verification is being performed (which can be very slow), clean
|
||||||
|
// up everything by closing the session and deleting the session object, and
|
||||||
|
// then shutting down the memory tracing subsystem. Otherwise, let it all
|
||||||
|
// leak because we're about to exit anyway.
|
||||||
IF_VERIFY() {
|
IF_VERIFY() {
|
||||||
|
set_session_context(NULL);
|
||||||
|
if (session != NULL)
|
||||||
|
checked_delete(session);
|
||||||
|
|
||||||
INFO("Ledger ended (Boost/libstdc++ may still hold memory)");
|
INFO("Ledger ended (Boost/libstdc++ may still hold memory)");
|
||||||
ledger::set_session_context();
|
shutdown_memory_tracing();
|
||||||
ledger::shutdown_memory_tracing();
|
|
||||||
} else {
|
} else {
|
||||||
|
// Don't free anything, just let it all leak.
|
||||||
INFO("Ledger ended");
|
INFO("Ledger ended");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,8 @@
|
||||||
#include "account.h"
|
#include "account.h"
|
||||||
#include "session.h"
|
#include "session.h"
|
||||||
|
|
||||||
|
#if defined(HAVE_LIBOFX)
|
||||||
|
|
||||||
#include <libofx.h>
|
#include <libofx.h>
|
||||||
|
|
||||||
namespace ledger {
|
namespace ledger {
|
||||||
|
|
@ -261,3 +263,5 @@ std::size_t ofx_parser_t::parse(std::istream& in,
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace ledger
|
} // namespace ledger
|
||||||
|
|
||||||
|
#endif HAVE_LIBOFX
|
||||||
|
|
|
||||||
|
|
@ -488,38 +488,7 @@ namespace {
|
||||||
out << std::endl << "--- Expression tree ---" << std::endl;
|
out << std::endl << "--- Expression tree ---" << std::endl;
|
||||||
expr.dump(out);
|
expr.dump(out);
|
||||||
|
|
||||||
out << std::endl << "--- Calculated value ---" << std::endl;
|
|
||||||
expr.calc(args).print(out);
|
|
||||||
out << std::endl;
|
|
||||||
|
|
||||||
return 0L;
|
|
||||||
}
|
|
||||||
|
|
||||||
value_t compile_command(call_scope_t& args)
|
|
||||||
{
|
|
||||||
var_t<string> arg(args, 0);
|
|
||||||
|
|
||||||
if (! arg) {
|
|
||||||
throw std::logic_error("Usage: compile TEXT");
|
|
||||||
return 1L;
|
|
||||||
}
|
|
||||||
|
|
||||||
report_t& report(find_scope<report_t>(args));
|
|
||||||
std::ostream& out(report.output_stream);
|
|
||||||
|
|
||||||
out << "--- Input text ---" << std::endl;
|
|
||||||
out << *arg << std::endl;
|
|
||||||
|
|
||||||
out << std::endl << "--- Text as parsed ---" << std::endl;
|
|
||||||
expr_t expr(*arg);
|
|
||||||
expr.print(out);
|
|
||||||
out << std::endl;
|
|
||||||
|
|
||||||
out << std::endl << "--- Expression tree ---" << std::endl;
|
|
||||||
expr.dump(out);
|
|
||||||
|
|
||||||
expr.compile(args);
|
expr.compile(args);
|
||||||
|
|
||||||
out << std::endl << "--- Compiled tree ---" << std::endl;
|
out << std::endl << "--- Compiled tree ---" << std::endl;
|
||||||
expr.dump(out);
|
expr.dump(out);
|
||||||
|
|
||||||
|
|
@ -680,11 +649,6 @@ expr_t::ptr_op_t report_t::lookup(const string& name)
|
||||||
return WRAP_FUNCTOR(period_command);
|
return WRAP_FUNCTOR(period_command);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'c':
|
|
||||||
if (std::strcmp(p, "compile") == 0)
|
|
||||||
return WRAP_FUNCTOR(compile_command);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'e':
|
case 'e':
|
||||||
if (std::strcmp(p, "eval") == 0)
|
if (std::strcmp(p, "eval") == 0)
|
||||||
return WRAP_FUNCTOR(eval_command);
|
return WRAP_FUNCTOR(eval_command);
|
||||||
|
|
|
||||||
|
|
@ -735,6 +735,8 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
value_t option_price_db_(call_scope_t& args) { // :
|
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();
|
session.price_db = args[0].as_string();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -70,7 +70,12 @@ void release_session_context()
|
||||||
}
|
}
|
||||||
|
|
||||||
session_t::session_t()
|
session_t::session_t()
|
||||||
: register_format
|
: 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(date) %-.20(payee) %-.23(account(23)) %!12(print_balance(amount_expr, 12, 67)) "
|
("%-.9(date) %-.20(payee) %-.23(account(23)) %!12(print_balance(amount_expr, 12, 67)) "
|
||||||
"%!12(print_balance(display_total, 12, 80, true))\n%/"
|
"%!12(print_balance(display_total, 12, 80, true))\n%/"
|
||||||
"%31|%-.23(account(23)) %!12(print_balance(amount_expr, 12, 67)) "
|
"%31|%-.23(account(23)) %!12(print_balance(amount_expr, 12, 67)) "
|
||||||
|
|
@ -116,6 +121,14 @@ session_t::session_t()
|
||||||
master(new account_t(NULL, ""))
|
master(new account_t(NULL, ""))
|
||||||
{
|
{
|
||||||
TRACE_CTOR(session_t, "");
|
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";
|
||||||
|
cache_file = home ? *home / ".ledger-cache" : "./.ledger-cache";
|
||||||
}
|
}
|
||||||
|
|
||||||
session_t::~session_t()
|
session_t::~session_t()
|
||||||
|
|
@ -159,6 +172,8 @@ void session_t::read_init()
|
||||||
if (! exists(*init_file))
|
if (! exists(*init_file))
|
||||||
throw_(std::logic_error, "Cannot read init file" << *init_file);
|
throw_(std::logic_error, "Cannot read init file" << *init_file);
|
||||||
|
|
||||||
|
TRACE_START(init, 1, "Read initialization file");
|
||||||
|
|
||||||
ifstream init(*init_file);
|
ifstream init(*init_file);
|
||||||
|
|
||||||
journal_t temp;
|
journal_t temp;
|
||||||
|
|
@ -167,12 +182,14 @@ void session_t::read_init()
|
||||||
temp.period_entries.size() > 0)
|
temp.period_entries.size() > 0)
|
||||||
throw_(parse_error, "Entries found in initialization file '" <<
|
throw_(parse_error, "Entries found in initialization file '" <<
|
||||||
init_file << "'");
|
init_file << "'");
|
||||||
|
|
||||||
|
TRACE_FINISH(init, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t session_t::read_data(journal_t& journal,
|
std::size_t session_t::read_data(journal_t& journal,
|
||||||
const string& master_account)
|
const string& master_account)
|
||||||
{
|
{
|
||||||
if (data_file.empty())
|
if (data_files.empty())
|
||||||
throw_(parse_error, "No journal file was specified (please use -f)");
|
throw_(parse_error, "No journal file was specified (please use -f)");
|
||||||
|
|
||||||
TRACE_START(session_parser, 1, "Parsed journal file");
|
TRACE_START(session_parser, 1, "Parsed journal file");
|
||||||
|
|
@ -210,33 +227,39 @@ std::size_t session_t::read_data(journal_t& journal,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUG("ledger.cache", "rejected cache, parsing " << data_file.string());
|
|
||||||
if (data_file == "-") {
|
|
||||||
use_cache = false;
|
|
||||||
journal.sources.push_back("/dev/stdin");
|
|
||||||
|
|
||||||
// To avoid problems with stdin and pipes, etc., we read the entire
|
foreach (const path& pathname, data_files) {
|
||||||
// file in beforehand into a memory buffer, and then parcel it out
|
DEBUG("ledger.cache", "rejected cache, parsing " << pathname.string());
|
||||||
// from there.
|
if (pathname == "-") {
|
||||||
std::ostringstream buffer;
|
use_cache = false;
|
||||||
|
journal.sources.push_back("/dev/stdin");
|
||||||
|
|
||||||
while (std::cin.good() && ! std::cin.eof()) {
|
// To avoid problems with stdin and pipes, etc., we read the entire
|
||||||
static char line[8192];
|
// file in beforehand into a memory buffer, and then parcel it out
|
||||||
std::cin.read(line, 8192);
|
// from there.
|
||||||
std::streamsize count = std::cin.gcount();
|
std::ostringstream buffer;
|
||||||
buffer.write(line, count);
|
|
||||||
|
while (std::cin.good() && ! std::cin.eof()) {
|
||||||
|
static char line[8192];
|
||||||
|
std::cin.read(line, 8192);
|
||||||
|
std::streamsize count = std::cin.gcount();
|
||||||
|
buffer.write(line, count);
|
||||||
|
}
|
||||||
|
buffer.flush();
|
||||||
|
|
||||||
|
std::istringstream buf_in(buffer.str());
|
||||||
|
|
||||||
|
entry_count += read_journal(journal, buf_in, "/dev/stdin", acct);
|
||||||
|
}
|
||||||
|
else if (exists(pathname)) {
|
||||||
|
entry_count += read_journal(journal, pathname, acct);
|
||||||
|
if (journal.price_db)
|
||||||
|
journal.sources.push_back(*journal.price_db);
|
||||||
|
clean_accounts();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw_(parse_error, "Could not open journal file '" << pathname << "'");
|
||||||
}
|
}
|
||||||
buffer.flush();
|
|
||||||
|
|
||||||
std::istringstream buf_in(buffer.str());
|
|
||||||
|
|
||||||
entry_count += read_journal(journal, buf_in, "/dev/stdin", acct);
|
|
||||||
}
|
|
||||||
else if (exists(data_file)) {
|
|
||||||
entry_count += read_journal(journal, data_file, acct);
|
|
||||||
if (journal.price_db)
|
|
||||||
journal.sources.push_back(*journal.price_db);
|
|
||||||
clean_accounts();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -71,12 +71,16 @@ class session_t : public noncopyable, public scope_t
|
||||||
public:
|
public:
|
||||||
static session_t * current;
|
static session_t * current;
|
||||||
|
|
||||||
scoped_ptr<report_t> current_report;
|
scoped_ptr<report_t> report;
|
||||||
|
|
||||||
path data_file;
|
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> init_file;
|
||||||
optional<path> cache_file;
|
optional<path> cache_file;
|
||||||
optional<path> price_db;
|
optional<path> price_db;
|
||||||
|
bool next_price_db_from_command_line;
|
||||||
|
bool saw_price_db_from_command_line;
|
||||||
|
|
||||||
string register_format;
|
string register_format;
|
||||||
string wide_register_format;
|
string wide_register_format;
|
||||||
|
|
@ -114,6 +118,11 @@ public:
|
||||||
session_t();
|
session_t();
|
||||||
virtual ~session_t();
|
virtual ~session_t();
|
||||||
|
|
||||||
|
void now_at_command_line(const bool truth) {
|
||||||
|
next_data_file_from_command_line = truth;
|
||||||
|
next_price_db_from_command_line = truth;
|
||||||
|
}
|
||||||
|
|
||||||
journal_t * create_journal() {
|
journal_t * create_journal() {
|
||||||
journal_t * journal = new journal_t;
|
journal_t * journal = new journal_t;
|
||||||
journals.push_back(journal);
|
journals.push_back(journal);
|
||||||
|
|
@ -243,11 +252,13 @@ See LICENSE file included with the distribution for details and disclaimer.\n";
|
||||||
|
|
||||||
value_t option_file_(call_scope_t& args) { // f
|
value_t option_file_(call_scope_t& args) { // f
|
||||||
assert(args.size() == 1);
|
assert(args.size() == 1);
|
||||||
|
if (next_data_file_from_command_line &&
|
||||||
// jww (2008-08-13): Add support for multiple files
|
! saw_data_file_from_command_line) {
|
||||||
data_file = args[0].as_string();
|
data_files.clear();
|
||||||
use_cache = false;
|
use_cache = false;
|
||||||
|
saw_data_file_from_command_line = true;
|
||||||
|
}
|
||||||
|
data_files.push_back(args[0].as_string());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
308
src/work.cc
Normal file
308
src/work.cc
Normal file
|
|
@ -0,0 +1,308 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2003-2009, John Wiegley. All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are
|
||||||
|
* met:
|
||||||
|
*
|
||||||
|
* - Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* - Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* - Neither the name of New Artisans LLC nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived from
|
||||||
|
* this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <ledger.h>
|
||||||
|
|
||||||
|
#include "work.h"
|
||||||
|
|
||||||
|
namespace ledger {
|
||||||
|
|
||||||
|
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) {
|
||||||
|
std::cerr << "Argument to --trace must be an integer."
|
||||||
|
<< std::endl;
|
||||||
|
throw int(1);
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void register_journal_parsers(session_t& session)
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
session.register_parser(new journal_t::binary_parser_t);
|
||||||
|
#endif
|
||||||
|
session.register_parser(new xml_parser_t);
|
||||||
|
session.register_parser(new gnucash_parser_t);
|
||||||
|
#ifdef HAVE_LIBOFX
|
||||||
|
session.register_parser(new ofx_parser_t);
|
||||||
|
#endif
|
||||||
|
session.register_parser(new qif_parser_t);
|
||||||
|
session.register_parser(new textual_parser_t);
|
||||||
|
}
|
||||||
|
|
||||||
|
void read_environment_settings(report_t& report, char * envp[])
|
||||||
|
{
|
||||||
|
TRACE_START(environment, 1, "Processed environment variables");
|
||||||
|
|
||||||
|
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);
|
||||||
|
if (const char * p = std::getenv("LEDGER_INIT"))
|
||||||
|
process_option("init-file", report, p);
|
||||||
|
if (const char * p = std::getenv("PRICE_HIST"))
|
||||||
|
process_option("price-db", report, p);
|
||||||
|
if (const char * p = std::getenv("PRICE_EXP"))
|
||||||
|
process_option("price-exp", report, p);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
TRACE_FINISH(environment, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
strings_list
|
||||||
|
read_command_line_arguments(report_t& report, int argc, char * argv[])
|
||||||
|
{
|
||||||
|
TRACE_START(arguments, 1, "Processed command-line arguments");
|
||||||
|
|
||||||
|
strings_list args;
|
||||||
|
process_arguments(argc - 1, argv + 1, report, args);
|
||||||
|
|
||||||
|
if (args.empty()) {
|
||||||
|
help(std::cout);
|
||||||
|
throw int(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
TRACE_FINISH(arguments, 1);
|
||||||
|
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
|
||||||
|
void normalize_session_options(session_t& session)
|
||||||
|
{
|
||||||
|
if (! session.cache_file)
|
||||||
|
session.use_cache = false;
|
||||||
|
|
||||||
|
DEBUG("ledger.session.cache", "1. use_cache = " << session.use_cache);
|
||||||
|
|
||||||
|
if (std::find(session.data_files.begin(),
|
||||||
|
session.data_files.end(), *session.cache_file) !=
|
||||||
|
session.data_files.end())
|
||||||
|
session.use_cache = false;
|
||||||
|
|
||||||
|
DEBUG("ledger.session.cache", "2. use_cache = " << session.use_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());
|
||||||
|
|
||||||
|
foreach (const path& pathname, session.data_files)
|
||||||
|
INFO("Journal file is " << pathname.string());
|
||||||
|
|
||||||
|
if (! session.use_cache)
|
||||||
|
INFO("Binary cache mechanism will not be used");
|
||||||
|
}
|
||||||
|
|
||||||
|
function_t look_for_precommand(report_t& report, const string& verb)
|
||||||
|
{
|
||||||
|
if (expr_t::ptr_op_t def = report.lookup(string("ledger_precmd_") + verb))
|
||||||
|
return def->as_function();
|
||||||
|
else
|
||||||
|
return function_t();
|
||||||
|
}
|
||||||
|
|
||||||
|
journal_t * read_journal_files(session_t& session)
|
||||||
|
{
|
||||||
|
INFO_START(journal, "Read journal file");
|
||||||
|
|
||||||
|
journal_t * journal(session.create_journal());
|
||||||
|
|
||||||
|
std::size_t count = session.read_data(*journal, session.report->account);
|
||||||
|
if (count == 0)
|
||||||
|
throw_(parse_error, "Failed to locate any journal entries; "
|
||||||
|
"did you specify a valid file with -f?");
|
||||||
|
|
||||||
|
INFO_FINISH(journal);
|
||||||
|
|
||||||
|
INFO("Found " << count << " entries");
|
||||||
|
|
||||||
|
TRACE_FINISH(entry_text, 1);
|
||||||
|
TRACE_FINISH(entry_details, 1);
|
||||||
|
TRACE_FINISH(entry_xacts, 1);
|
||||||
|
TRACE_FINISH(entries, 1);
|
||||||
|
TRACE_FINISH(session_parser, 1);
|
||||||
|
TRACE_FINISH(parsing_total, 1);
|
||||||
|
|
||||||
|
return journal;
|
||||||
|
}
|
||||||
|
|
||||||
|
function_t look_for_command(report_t& report, const string& verb)
|
||||||
|
{
|
||||||
|
if (expr_t::ptr_op_t def = report.lookup(string("ledger_cmd_") + verb))
|
||||||
|
return def->as_function();
|
||||||
|
else
|
||||||
|
return function_t();
|
||||||
|
}
|
||||||
|
|
||||||
|
void normalize_report_options(report_t& report, const string& verb)
|
||||||
|
{
|
||||||
|
#if 1
|
||||||
|
// Patch up some of the reporting options based on what kind of
|
||||||
|
// command it was.
|
||||||
|
|
||||||
|
// jww (2008-08-14): This code really needs to be rationalized away
|
||||||
|
// for 3.0.
|
||||||
|
|
||||||
|
if (verb == "print" || verb == "entry" || verb == "dump") {
|
||||||
|
report.show_related = true;
|
||||||
|
report.show_all_related = true;
|
||||||
|
}
|
||||||
|
else if (verb == "equity") {
|
||||||
|
report.show_subtotal = true;
|
||||||
|
}
|
||||||
|
else if (report.show_related) {
|
||||||
|
if (verb[0] == 'r') {
|
||||||
|
report.show_inverted = true;
|
||||||
|
} else {
|
||||||
|
report.show_subtotal = true;
|
||||||
|
report.show_all_related = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (verb[0] != 'b' && verb[0] != 'r')
|
||||||
|
amount_t::keep_base = true;
|
||||||
|
|
||||||
|
// Setup the default value for the display predicate
|
||||||
|
|
||||||
|
if (report.display_predicate.empty()) {
|
||||||
|
if (verb[0] == 'b') {
|
||||||
|
if (! report.show_empty)
|
||||||
|
report.display_predicate = "total";
|
||||||
|
if (! report.show_subtotal) {
|
||||||
|
if (! report.display_predicate.empty())
|
||||||
|
report.display_predicate += "&";
|
||||||
|
report.display_predicate += "depth<=1";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (verb == "equity") {
|
||||||
|
report.display_predicate = "amount_expr"; // jww (2008-08-14): ???
|
||||||
|
}
|
||||||
|
else if (verb[0] == 'r' && ! report.show_empty) {
|
||||||
|
report.display_predicate = "amount";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Now setup the various formatting strings
|
||||||
|
|
||||||
|
// jww (2008-08-14): I hear a song, and it's sound is "HaAaaCcK"
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
if (! date_output_format.empty())
|
||||||
|
date_t::output_format = date_output_format;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
amount_t::keep_price = report.keep_price;
|
||||||
|
amount_t::keep_date = report.keep_date;
|
||||||
|
amount_t::keep_tag = report.keep_tag;
|
||||||
|
|
||||||
|
if (! report.report_period.empty() && ! report.sort_all)
|
||||||
|
report.entry_sort = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void create_output_stream(report_t& report)
|
||||||
|
{
|
||||||
|
report.output_stream.initialize(report.output_file, report.pager_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
void invoke_command_verb(report_t& report,
|
||||||
|
function_t& command,
|
||||||
|
string_iterator args_begin,
|
||||||
|
string_iterator args_end)
|
||||||
|
{
|
||||||
|
// Create an argument scope containing the report command's
|
||||||
|
// arguments, and then invoke the command.
|
||||||
|
|
||||||
|
call_scope_t command_args(report);
|
||||||
|
|
||||||
|
for (string_iterator i = args_begin; i != args_end; i++)
|
||||||
|
command_args.push_back(string_value(*i));
|
||||||
|
|
||||||
|
INFO_START(command, "Finished executing command");
|
||||||
|
|
||||||
|
command(command_args);
|
||||||
|
|
||||||
|
INFO_FINISH(command);
|
||||||
|
}
|
||||||
|
|
||||||
|
void write_binary_cache(session_t& session, journal_t * journal)
|
||||||
|
{
|
||||||
|
// 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");
|
||||||
|
|
||||||
|
ofstream stream(*session.cache_file);
|
||||||
|
#if 0
|
||||||
|
// jww (2009-01-31): NYI
|
||||||
|
journal->write(stream);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
TRACE_FINISH(binary_cache, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace ledger
|
||||||
65
src/work.h
Normal file
65
src/work.h
Normal file
|
|
@ -0,0 +1,65 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2003-2009, John Wiegley. All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* - Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* - Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* - Neither the name of New Artisans LLC nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived from
|
||||||
|
* this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file work.h
|
||||||
|
* @author John Wiegley
|
||||||
|
*
|
||||||
|
* @brief Contains the top-level functions used by main.cc
|
||||||
|
*/
|
||||||
|
#ifndef _WORK_H
|
||||||
|
#define _WORK_H
|
||||||
|
|
||||||
|
namespace ledger {
|
||||||
|
|
||||||
|
typedef strings_list::iterator string_iterator;
|
||||||
|
typedef std::pair<string_iterator, string_iterator> string_iterator_pair;
|
||||||
|
|
||||||
|
void handle_debug_options(int argc, char * argv[]);
|
||||||
|
void register_journal_parsers(session_t& session);
|
||||||
|
void read_environment_settings(report_t& report, char * envp[]);
|
||||||
|
strings_list read_command_line_arguments(report_t& report,
|
||||||
|
int argc, char * argv[]);
|
||||||
|
void normalize_session_options(session_t& session);
|
||||||
|
function_t look_for_precommand(report_t& report, const string& verb);
|
||||||
|
journal_t * read_journal_files(session_t& session);
|
||||||
|
function_t look_for_command(report_t& report, const string& verb);
|
||||||
|
void normalize_report_options(report_t& report, const string& verb);
|
||||||
|
void create_output_stream(report_t& report);
|
||||||
|
void invoke_command_verb(report_t& report,
|
||||||
|
function_t& command,
|
||||||
|
string_iterator args_begin,
|
||||||
|
string_iterator args_end);
|
||||||
|
void write_binary_cache(session_t& session, journal_t * journal);
|
||||||
|
|
||||||
|
} // namespace ledger
|
||||||
|
|
||||||
|
#endif // _WORK_H
|
||||||
Loading…
Add table
Reference in a new issue