diff options
author | John Wiegley <johnw@newartisans.com> | 2005-02-09 05:05:24 +0000 |
---|---|---|
committer | John Wiegley <johnw@newartisans.com> | 2008-04-13 02:40:54 -0400 |
commit | ed000a6967be06bf9e767e7375d2a5ce85c22d94 (patch) | |
tree | 69d573b99f2bc1422011cc39abc5342bed2a8b40 | |
parent | d8f35f3152aae177bf0848f6e1e1429600730bb1 (diff) | |
download | fork-ledger-ed000a6967be06bf9e767e7375d2a5ce85c22d94.tar.gz fork-ledger-ed000a6967be06bf9e767e7375d2a5ce85c22d94.tar.bz2 fork-ledger-ed000a6967be06bf9e767e7375d2a5ce85c22d94.zip |
Added support for each entry to remember: the file it came from, and
the beginning and ending character positions of that entry within the
file. This makes it possible to reproduce the input exactly, with
only the changed entries updated.
-rw-r--r-- | journal.cc | 13 | ||||
-rw-r--r-- | journal.h | 29 | ||||
-rw-r--r-- | textual.cc | 105 |
3 files changed, 135 insertions, 12 deletions
@@ -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) @@ -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); @@ -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 |