summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/global.cc3
-rw-r--r--src/global.h8
-rw-r--r--src/journal.cc97
-rw-r--r--src/journal.h12
-rw-r--r--src/py_journal.cc5
-rw-r--r--src/scope.cc2
-rw-r--r--src/scope.h2
-rw-r--r--src/session.cc46
-rw-r--r--src/session.h8
9 files changed, 118 insertions, 65 deletions
diff --git a/src/global.cc b/src/global.cc
index 97a46cce..2103e32c 100644
--- a/src/global.cc
+++ b/src/global.cc
@@ -67,6 +67,7 @@ global_scope_t::global_scope_t(char ** envp)
// open document, with a separate report_t object for each report it
// generated.
report_stack.push_front(new report_t(session()));
+ scope_t::default_scope = &report();
// Read the user's options, in the following order:
//
@@ -111,7 +112,7 @@ void global_scope_t::read_init()
ifstream init(init_file);
- if (session().read_journal(init_file, NULL, &report()) > 0 ||
+ if (session().journal->read(init_file, NULL, &report()) > 0 ||
session().journal->auto_xacts.size() > 0 ||
session().journal->period_xacts.size() > 0) {
throw_(parse_error, _("Transactions found in initialization file '%1'")
diff --git a/src/global.h b/src/global.h
index 34577656..31a0a480 100644
--- a/src/global.h
+++ b/src/global.h
@@ -75,10 +75,14 @@ public:
void push_report() {
report_stack.push_front(new report_t(report_stack.front()));
+ scope_t::default_scope = &report();
}
void pop_report() {
- if (! report_stack.empty())
- report_stack.pop_front();
+ assert(! report_stack.empty());
+ report_stack.pop_front();
+ // There should always be the "default report" waiting on the stack.
+ assert(! report_stack.empty());
+ scope_t::default_scope = &report();
}
void report_error(const std::exception& err);
diff --git a/src/journal.cc b/src/journal.cc
index 4d6e084e..31557635 100644
--- a/src/journal.cc
+++ b/src/journal.cc
@@ -41,23 +41,23 @@
namespace ledger {
journal_t::journal_t()
- : master(new account_t), basket(NULL), was_loaded(false),
- commodity_pool(new commodity_pool_t)
{
TRACE_CTOR(journal_t, "");
+ initialize();
+}
- // Add time commodity conversions, so that timelog's may be parsed
- // in terms of seconds, but reported as minutes or hours.
- if (commodity_t * commodity = commodity_pool->create("s"))
- commodity->add_flags(COMMODITY_BUILTIN | COMMODITY_NOMARKET);
- else
- assert(false);
+journal_t::journal_t(const path& pathname)
+{
+ TRACE_CTOR(journal_t, "path");
+ initialize();
+ read(pathname);
+}
- // Add a "percentile" commodity
- if (commodity_t * commodity = commodity_pool->create("%"))
- commodity->add_flags(COMMODITY_BUILTIN | COMMODITY_NOMARKET);
- else
- assert(false);
+journal_t::journal_t(const string& str)
+{
+ TRACE_CTOR(journal_t, "string");
+ initialize();
+ read(str);
}
journal_t::~journal_t()
@@ -80,6 +80,28 @@ journal_t::~journal_t()
commodity_pool.reset();
}
+void journal_t::initialize()
+{
+ master = new account_t;
+ basket = NULL;
+ was_loaded = false;
+
+ commodity_pool.reset(new commodity_pool_t);
+
+ // Add time commodity conversions, so that timelog's may be parsed
+ // in terms of seconds, but reported as minutes or hours.
+ if (commodity_t * commodity = commodity_pool->create("s"))
+ commodity->add_flags(COMMODITY_BUILTIN | COMMODITY_NOMARKET);
+ else
+ assert(false);
+
+ // Add a "percentile" commodity
+ if (commodity_t * commodity = commodity_pool->create("%"))
+ commodity->add_flags(COMMODITY_BUILTIN | COMMODITY_NOMARKET);
+ else
+ assert(false);
+}
+
void journal_t::add_account(account_t * acct)
{
master->add_account(acct);
@@ -134,6 +156,55 @@ bool journal_t::remove_xact(xact_t * xact)
return true;
}
+std::size_t journal_t::read(std::istream& in,
+ const path& pathname,
+ account_t * master_alt,
+ scope_t * scope)
+{
+ std::size_t count = 0;
+ try {
+ if (! scope)
+ scope = scope_t::default_scope;
+
+ if (! scope)
+ throw_(std::runtime_error,
+ _("No default scope in which to read journal file '%1'")
+ << pathname);
+
+ value_t strict = expr_t("strict").calc(*scope);
+
+ count = parse(in, *scope, master_alt ? master_alt : master,
+ &pathname, strict.to_boolean());
+ }
+ catch (...) {
+ clear_xdata();
+ throw;
+ }
+
+ // xdata may have been set for some accounts and transaction due to the use
+ // of balance assertions or other calculations performed in valexpr-based
+ // posting amounts.
+ clear_xdata();
+
+ return count;
+}
+
+std::size_t journal_t::read(const path& pathname,
+ account_t * master,
+ scope_t * scope)
+{
+ path filename = resolve_path(pathname);
+
+ if (! exists(filename))
+ throw_(std::runtime_error,
+ _("Cannot read journal file '%1'") << filename);
+
+ ifstream stream(filename);
+ std::size_t count = read(stream, filename, master, scope);
+ sources.push_back(fileinfo_t(filename));
+ return count;
+}
+
void journal_t::clear_xdata()
{
foreach (xact_t * xact, xacts)
diff --git a/src/journal.h b/src/journal.h
index 60d703e6..e2af0dde 100644
--- a/src/journal.h
+++ b/src/journal.h
@@ -126,8 +126,12 @@ public:
hooks_t<xact_finalizer_t, xact_t> xact_finalize_hooks;
journal_t();
+ journal_t(const path& pathname);
+ journal_t(const string& str);
~journal_t();
+ void initialize();
+
std::list<fileinfo_t>::iterator sources_begin() {
return sources.begin();
}
@@ -171,6 +175,14 @@ public:
xact_finalize_hooks.remove_hook(finalizer);
}
+ std::size_t read(std::istream& in,
+ const path& pathname,
+ account_t * master = NULL,
+ scope_t * scope = NULL);
+ std::size_t read(const path& pathname,
+ account_t * master = NULL,
+ scope_t * scope = NULL);
+
std::size_t parse(std::istream& in,
scope_t& session_scope,
account_t * master = NULL,
diff --git a/src/py_journal.cc b/src/py_journal.cc
index bc79101b..a9789840 100644
--- a/src/py_journal.cc
+++ b/src/py_journal.cc
@@ -171,6 +171,8 @@ namespace {
void export_journal()
{
class_< journal_t::fileinfo_t > ("FileInfo")
+ .def(init<path>())
+
.add_property("filename",
make_getter(&journal_t::fileinfo_t::filename),
make_setter(&journal_t::fileinfo_t::filename))
@@ -186,6 +188,9 @@ void export_journal()
;
class_< journal_t, boost::noncopyable > ("Journal")
+ .def(init<path>())
+ .def(init<string>())
+
.add_property("master", make_getter(&journal_t::master,
return_internal_reference<1>()))
.add_property("basket",
diff --git a/src/scope.cc b/src/scope.cc
index 998eac64..99f6b669 100644
--- a/src/scope.cc
+++ b/src/scope.cc
@@ -35,6 +35,8 @@
namespace ledger {
+scope_t * scope_t::default_scope = NULL;
+
void symbol_scope_t::define(const symbol_t::kind_t kind,
const string& name, expr_t::ptr_op_t def)
{
diff --git a/src/scope.h b/src/scope.h
index 7cf89c3e..c2c9df20 100644
--- a/src/scope.h
+++ b/src/scope.h
@@ -113,6 +113,8 @@ private:
class scope_t
{
public:
+ static scope_t * default_scope;
+
explicit scope_t() {
TRACE_CTOR(scope_t, "");
}
diff --git a/src/session.cc b/src/session.cc
index 8cbef1e6..afc092f1 100644
--- a/src/session.cc
+++ b/src/session.cc
@@ -72,35 +72,6 @@ session_t::session_t()
HANDLER(price_db_).on(none, path("./.pricedb").string());
}
-std::size_t session_t::read_journal(std::istream& in,
- const path& pathname,
- account_t * master,
- scope_t * scope)
-{
- if (! master)
- master = journal->master;
-
- std::size_t count = journal->parse(in, scope ? *scope : *this,
- master, &pathname, HANDLED(strict));
-
- // remove calculated totals and flags
- clean_posts();
- clean_accounts();
-
- return count;
-}
-
-std::size_t session_t::read_journal(const path& pathname,
- account_t * master,
- scope_t * scope)
-{
- if (! exists(pathname))
- throw_(std::logic_error, _("Cannot read file '%1'") << pathname);
-
- ifstream stream(pathname);
- return read_journal(stream, pathname, master, scope);
-}
-
std::size_t session_t::read_data(const string& master_account)
{
bool populated_data_files = false;
@@ -144,16 +115,14 @@ std::size_t session_t::read_data(const string& master_account)
cache->load(journal))) {
if (price_db_path) {
if (exists(*price_db_path)) {
- if (read_journal(*price_db_path) > 0)
+ if (journal->read(*price_db_path) > 0)
throw_(parse_error, _("Transactions not allowed in price history file"));
- journal->sources.push_back(journal_t::fileinfo_t(*price_db_path));
}
HANDLER(file_).data_files.remove(*price_db_path);
}
foreach (const path& pathname, HANDLER(file_).data_files) {
- path filename = resolve_path(pathname);
- if (filename == "-") {
+ if (pathname == "-") {
// To avoid problems with stdin and pipes, etc., we read the entire
// file in beforehand into a memory buffer, and then parcel it out
// from there.
@@ -169,15 +138,10 @@ std::size_t session_t::read_data(const string& master_account)
std::istringstream buf_in(buffer.str());
- xact_count += read_journal(buf_in, "/dev/stdin", acct);
+ xact_count += journal->read(buf_in, "/dev/stdin", acct);
journal->sources.push_back(journal_t::fileinfo_t());
- }
- else if (exists(filename)) {
- xact_count += read_journal(filename, acct);
- journal->sources.push_back(journal_t::fileinfo_t(filename));
- }
- else {
- throw_(parse_error, _("Could not read journal file '%1'") << filename);
+ } else {
+ xact_count += journal->read(pathname, acct);
}
}
diff --git a/src/session.h b/src/session.h
index 8e73b660..7c5d47dd 100644
--- a/src/session.h
+++ b/src/session.h
@@ -80,14 +80,6 @@ public:
flush_on_next_data_file = truth;
}
- std::size_t read_journal(std::istream& in,
- const path& pathname,
- account_t * master = NULL,
- scope_t * scope = NULL);
- std::size_t read_journal(const path& pathname,
- account_t * master = NULL,
- scope_t * scope = NULL);
-
std::size_t read_data(const string& master_account = "");
void read_journal_files();