summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--journal.cc13
-rw-r--r--journal.h29
-rw-r--r--textual.cc105
3 files changed, 135 insertions, 12 deletions
diff --git a/journal.cc b/journal.cc
index d57734b5..1af0342f 100644
--- a/journal.cc
+++ b/journal.cc
@@ -165,7 +165,7 @@ void entry_t::add_transaction(transaction_t * xact)
bool entry_t::valid() const
{
- if (! date)
+ if (! date || ! journal)
return false;
if (state != UNCLEARED && state != CLEARED && state != PENDING)
@@ -276,6 +276,7 @@ account_t * account_t::find_account(const std::string& name,
return NULL;
account = new account_t(this, first);
+ account->journal = journal;
std::pair<accounts_map::iterator, bool> result
= accounts.insert(accounts_pair(first, account));
@@ -338,7 +339,7 @@ std::ostream& operator<<(std::ostream& out, const account_t& account)
bool account_t::valid() const
{
- if (depth > 256)
+ if (depth > 256 || ! journal)
return false;
for (accounts_map::const_iterator i = accounts.begin();
@@ -398,6 +399,7 @@ bool journal_t::add_entry(entry_t * entry)
return false;
entries.push_back(entry);
+ entry->journal = this;
for (transactions_list::const_iterator i = entry->transactions.begin();
i != entry->transactions.end();
@@ -422,6 +424,7 @@ bool journal_t::remove_entry(entry_t * entry)
return false;
entries.erase(i);
+ entry->journal = NULL;
return true;
}
@@ -686,6 +689,7 @@ void export_journal()
.def(self == self)
.def(self != self)
+ .def_readonly("journal", &account_t::journal)
.add_property("parent",
make_getter(&account_t::parent,
return_internal_reference<1>()))
@@ -739,6 +743,11 @@ void export_journal()
.def("__getitem__", transactions_getitem,
return_internal_reference<1>())
+ .def_readonly("journal", &entry_base_t::journal)
+ .def_readonly("src_idx", &entry_base_t::src_idx)
+ .def_readonly("beg_pos", &entry_base_t::beg_pos)
+ .def_readonly("end_pos", &entry_base_t::end_pos)
+
.def("add_transaction", py_add_transaction)
.def("remove_transaction", &entry_base_t::remove_transaction)
diff --git a/journal.h b/journal.h
index 75ae35fa..733540c1 100644
--- a/journal.h
+++ b/journal.h
@@ -74,12 +74,18 @@ class transaction_t
bool valid() const;
};
+class journal_t;
+
typedef std::list<transaction_t *> transactions_list;
class entry_base_t
{
public:
- transactions_list transactions;
+ journal_t * journal;
+ unsigned long src_idx;
+ std::istream::pos_type beg_pos;
+ std::istream::pos_type end_pos;
+ transactions_list transactions;
entry_base_t() {
DEBUG_PRINT("ledger.memory.ctors", "ctor entry_base_t");
@@ -216,14 +222,15 @@ class account_t
public:
typedef unsigned long ident_t;
- account_t * parent;
- std::string name;
- std::string note;
- unsigned short depth;
- accounts_map accounts;
+ journal_t * journal;
+ account_t * parent;
+ std::string name;
+ std::string note;
+ unsigned short depth;
+ accounts_map accounts;
- mutable void * data;
- mutable ident_t ident;
+ mutable void * data;
+ mutable ident_t ident;
mutable std::string _fullname;
account_t(account_t * _parent = NULL,
@@ -247,9 +254,11 @@ class account_t
void add_account(account_t * acct) {
accounts.insert(accounts_pair(acct->name, acct));
+ acct->journal = journal;
}
bool remove_account(account_t * acct) {
accounts_map::size_type n = accounts.erase(acct->name);
+ acct->journal = NULL;
return n > 0;
}
@@ -325,6 +334,7 @@ class journal_t
journal_t() {
DEBUG_PRINT("ledger.memory.ctors", "ctor journal_t");
master = new account_t(NULL, "");
+ master->journal = this;
item_pool = item_pool_end = NULL;
}
~journal_t();
@@ -338,9 +348,11 @@ class journal_t
void add_account(account_t * acct) {
master->add_account(acct);
+ acct->journal = this;
}
bool remove_account(account_t * acct) {
return master->remove_account(acct);
+ acct->journal = NULL;
}
account_t * find_account(const std::string& name, bool auto_create = true) {
@@ -350,6 +362,7 @@ class journal_t
account_t * account = master->find_account(name, auto_create);
accounts_cache.insert(accounts_pair(name, account));
+ account->journal = this;
return account;
}
account_t * find_account_re(const std::string& regexp);
diff --git a/textual.cc b/textual.cc
index c15b7701..339d7a59 100644
--- a/textual.cc
+++ b/textual.cc
@@ -7,6 +7,7 @@
#include "config.h"
#include "timing.h"
#include "util.h"
+#include "acconf.h"
#ifdef USE_BOOST_PYTHON
#include "py_eval.h"
#endif
@@ -308,6 +309,8 @@ unsigned int textual_parser_t::parse(std::istream& in,
while (in.good() && ! in.eof()) {
try {
+ std::istream::pos_type beg_pos = in.tellg();
+
in.getline(line, MAX_LINE);
if (in.eof())
break;
@@ -477,11 +480,15 @@ unsigned int textual_parser_t::parse(std::istream& in,
auto_entry_t * ae = new auto_entry_t(skip_ws(line + 1));
if (parse_transactions(in, account_stack.front(), *ae, "automated")) {
- if (ae->finalize())
+ if (ae->finalize()) {
journal->auto_entries.push_back(ae);
- else
+ ae->src_idx = journal->sources.size() - 1;
+ ae->beg_pos = beg_pos;
+ ae->end_pos = in.tellg();
+ } else {
throw parse_error(path, linenum,
"Automated entry failed to balance");
+ }
}
break;
}
@@ -496,6 +503,9 @@ unsigned int textual_parser_t::parse(std::istream& in,
if (pe->finalize()) {
extend_entry_base(journal, *pe);
journal->period_entries.push_back(pe);
+ pe->src_idx = journal->sources.size() - 1;
+ pe->beg_pos = beg_pos;
+ pe->end_pos = in.tellg();
} else {
throw parse_error(path, linenum, "Period entry failed to balance");
}
@@ -543,9 +553,13 @@ unsigned int textual_parser_t::parse(std::istream& in,
default: {
unsigned int first_line = linenum;
+
if (entry_t * entry = parse_entry(in, line, account_stack.front(),
*this)) {
if (journal->add_entry(entry)) {
+ entry->src_idx = journal->sources.size() - 1;
+ entry->beg_pos = beg_pos;
+ entry->end_pos = in.tellg();
count++;
} else {
delete entry;
@@ -584,6 +598,93 @@ unsigned int textual_parser_t::parse(std::istream& in,
return count;
}
+void write_textual_journal(journal_t& journal, std::string path,
+ item_handler<transaction_t>& formatter,
+ std::ostream& out)
+{
+ unsigned long index = 0;
+ std::string found;
+ char buf1[PATH_MAX];
+ char buf2[PATH_MAX];
+
+#ifdef HAVE_REALPATH
+ realpath(path.c_str(), buf1);
+ for (strings_list::iterator i = journal.sources.begin();
+ i != journal.sources.end();
+ i++) {
+ realpath((*i).c_str(), buf2);
+ if (std::strcmp(buf1, buf2) == 0) {
+ found = *i;
+ break;
+ }
+ index++;
+ }
+#else
+ for (strings_list::iterator i = journal.sources.begin();
+ i != journal.sources.end();
+ i++) {
+ if (path == *i) {
+ found = *i;
+ break;
+ }
+ index++;
+ }
+#endif
+
+ if (found.empty())
+ throw error(std::string("Journal does not refer to file '") +
+ found + "'");
+
+ entries_list::iterator el = journal.entries.begin();
+ auto_entries_list::iterator al = journal.auto_entries.begin();
+ period_entries_list::iterator pl = journal.period_entries.begin();
+
+ std::istream::pos_type pos = 0;
+ std::istream::pos_type jump_to;
+
+ format_t hdr_fmt(config.write_hdr_format);
+
+ std::ifstream in(found.c_str());
+ while (! in.eof()) {
+ entry_base_t * base = NULL;
+ if (el != journal.entries.end() &&
+ pos == (*el)->beg_pos) {
+ hdr_fmt.format(out, details_t(**el));
+ base = *el++;
+ }
+ else if (al != journal.auto_entries.end() &&
+ pos == (*al)->beg_pos) {
+ out << "= " << (*al)->predicate_string << '\n';
+ base = *al++;
+ }
+ else if (pl != journal.period_entries.end() &&
+ pos == (*pl)->beg_pos) {
+ out << "~ " << (*pl)->period_string << '\n';
+ base = *pl++;
+ }
+
+ char c;
+ if (base) {
+ for (transactions_list::iterator x = base->transactions.begin();
+ x != base->transactions.end();
+ x++)
+ transaction_xdata(**x).dflags |= TRANSACTION_TO_DISPLAY;
+
+ walk_transactions(base->transactions, formatter);
+ formatter.flush();
+
+ while (pos < base->end_pos) {
+ in.get(c);
+ pos = in.tellg(); // pos++;
+ }
+ } else {
+ in.get(c);
+ pos = in.tellg(); // pos++;
+ out.put(c);
+ }
+ }
+}
+
} // namespace ledger
#ifdef USE_BOOST_PYTHON