moved entry hooking mechanism to journal_t; further improvements to "entry"
This commit is contained in:
parent
02580c2efb
commit
c57bfb72c3
9 changed files with 191 additions and 147 deletions
24
autoxact.cc
24
autoxact.cc
|
|
@ -2,10 +2,10 @@
|
||||||
|
|
||||||
namespace ledger {
|
namespace ledger {
|
||||||
|
|
||||||
void automated_transaction_t::extend_entry(entry_t * entry)
|
void automated_transaction_t::extend_entry(entry_t& entry)
|
||||||
{
|
{
|
||||||
transactions_deque initial_xacts(entry->transactions.begin(),
|
transactions_deque initial_xacts(entry.transactions.begin(),
|
||||||
entry->transactions.end());
|
entry.transactions.end());
|
||||||
|
|
||||||
for (transactions_deque::iterator i = initial_xacts.begin();
|
for (transactions_deque::iterator i = initial_xacts.begin();
|
||||||
i != initial_xacts.end();
|
i != initial_xacts.end();
|
||||||
|
|
@ -23,13 +23,13 @@ void automated_transaction_t::extend_entry(entry_t * entry)
|
||||||
transaction_t * xact
|
transaction_t * xact
|
||||||
= new transaction_t((*t)->account, amt,
|
= new transaction_t((*t)->account, amt,
|
||||||
(*t)->flags | TRANSACTION_AUTO);
|
(*t)->flags | TRANSACTION_AUTO);
|
||||||
entry->add_transaction(xact);
|
entry.add_transaction(xact);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
automated_transactions_t * current_auto_xacts = NULL;
|
automated_transactions_t * current_auto_xacts = NULL;
|
||||||
|
|
||||||
bool handle_auto_xacts(entry_t * entry)
|
bool handle_auto_xacts(entry_t& entry)
|
||||||
{
|
{
|
||||||
if (current_auto_xacts &&
|
if (current_auto_xacts &&
|
||||||
! current_auto_xacts->automated_transactions.empty())
|
! current_auto_xacts->automated_transactions.empty())
|
||||||
|
|
@ -39,3 +39,17 @@ bool handle_auto_xacts(entry_t * entry)
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace ledger
|
} // namespace ledger
|
||||||
|
|
||||||
|
#ifdef USE_BOOST_PYTHON
|
||||||
|
|
||||||
|
#include <boost/python.hpp>
|
||||||
|
#include <Python.h>
|
||||||
|
|
||||||
|
using namespace boost::python;
|
||||||
|
using namespace ledger;
|
||||||
|
|
||||||
|
void export_autoxact() {
|
||||||
|
def("handle_auto_xacts", handle_auto_xacts);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // USE_BOOST_PYTHON
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ public:
|
||||||
delete *i;
|
delete *i;
|
||||||
}
|
}
|
||||||
|
|
||||||
void extend_entry(entry_t * entry);
|
void extend_entry(entry_t& entry);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -63,7 +63,7 @@ public:
|
||||||
delete *i;
|
delete *i;
|
||||||
}
|
}
|
||||||
|
|
||||||
void extend_entry(entry_t * entry) {
|
void extend_entry(entry_t& entry) {
|
||||||
for (automated_transactions_deque::iterator i
|
for (automated_transactions_deque::iterator i
|
||||||
= automated_transactions.begin();
|
= automated_transactions.begin();
|
||||||
i != automated_transactions.end();
|
i != automated_transactions.end();
|
||||||
|
|
@ -90,7 +90,7 @@ public:
|
||||||
|
|
||||||
extern automated_transactions_t * current_auto_xacts;
|
extern automated_transactions_t * current_auto_xacts;
|
||||||
|
|
||||||
bool handle_auto_xacts(entry_t * entry);
|
bool handle_auto_xacts(entry_t& entry);
|
||||||
|
|
||||||
} // namespace ledger
|
} // namespace ledger
|
||||||
|
|
||||||
|
|
|
||||||
121
journal.cc
121
journal.cc
|
|
@ -120,6 +120,93 @@ bool entry_t::remove_transaction(transaction_t * xact)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool finalize_entry(entry_t& entry)
|
||||||
|
{
|
||||||
|
// Scan through and compute the total balance for the entry. This
|
||||||
|
// is used for auto-calculating the value of entries with no cost,
|
||||||
|
// and the per-unit price of unpriced commodities.
|
||||||
|
|
||||||
|
value_t balance;
|
||||||
|
|
||||||
|
bool no_amounts = true;
|
||||||
|
for (transactions_list::const_iterator x = entry.transactions.begin();
|
||||||
|
x != entry.transactions.end();
|
||||||
|
x++)
|
||||||
|
if (! ((*x)->flags & TRANSACTION_VIRTUAL) ||
|
||||||
|
((*x)->flags & TRANSACTION_BALANCE)) {
|
||||||
|
amount_t * p = (*x)->cost ? (*x)->cost : &(*x)->amount;
|
||||||
|
if (*p) {
|
||||||
|
if (no_amounts) {
|
||||||
|
balance = *p;
|
||||||
|
no_amounts = false;
|
||||||
|
} else {
|
||||||
|
balance += *p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If it's a null entry, then let the user have their fun
|
||||||
|
if (no_amounts)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// If one transaction of a two-line transaction is of a different
|
||||||
|
// commodity than the others, and it has no per-unit price,
|
||||||
|
// determine its price by dividing the unit count into the value of
|
||||||
|
// the balance. This is done for the last eligible commodity.
|
||||||
|
|
||||||
|
if (balance.type == value_t::BALANCE &&
|
||||||
|
((balance_t *) balance.data)->amounts.size() == 2)
|
||||||
|
for (transactions_list::const_iterator x = entry.transactions.begin();
|
||||||
|
x != entry.transactions.end();
|
||||||
|
x++) {
|
||||||
|
if ((*x)->cost || ((*x)->flags & TRANSACTION_VIRTUAL))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (amounts_map::const_iterator i
|
||||||
|
= ((balance_t *) balance.data)->amounts.begin();
|
||||||
|
i != ((balance_t *) balance.data)->amounts.end();
|
||||||
|
i++)
|
||||||
|
if ((*i).second.commodity() != (*x)->amount.commodity()) {
|
||||||
|
assert((*x)->amount);
|
||||||
|
balance -= (*x)->amount;
|
||||||
|
assert(! (*x)->cost);
|
||||||
|
(*x)->cost = new amount_t(- (*i).second);
|
||||||
|
balance += *(*x)->cost;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Walk through each of the transactions, fixing up any that we
|
||||||
|
// can, and performing any on-the-fly calculations.
|
||||||
|
|
||||||
|
bool empty_allowed = true;
|
||||||
|
|
||||||
|
for (transactions_list::const_iterator x = entry.transactions.begin();
|
||||||
|
x != entry.transactions.end();
|
||||||
|
x++) {
|
||||||
|
if ((*x)->amount || ((*x)->flags & TRANSACTION_VIRTUAL))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (! empty_allowed || ! balance || balance.type != value_t::AMOUNT)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
empty_allowed = false;
|
||||||
|
|
||||||
|
// If one transaction gives no value at all -- and all the
|
||||||
|
// rest are of the same commodity -- then its value is the
|
||||||
|
// inverse of the computed value of the others.
|
||||||
|
|
||||||
|
(*x)->amount = *((amount_t *) balance.data);
|
||||||
|
(*x)->amount.negate();
|
||||||
|
|
||||||
|
balance = 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ! balance;
|
||||||
|
}
|
||||||
|
|
||||||
bool entry_t::valid() const
|
bool entry_t::valid() const
|
||||||
{
|
{
|
||||||
if (! date || date == -1)
|
if (! date || date == -1)
|
||||||
|
|
@ -296,6 +383,11 @@ journal_t::~journal_t()
|
||||||
|
|
||||||
bool journal_t::add_entry(entry_t * entry)
|
bool journal_t::add_entry(entry_t * entry)
|
||||||
{
|
{
|
||||||
|
if (! run_hooks(entry_finalize_hooks, *entry)) {
|
||||||
|
delete entry;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
entries.push_back(entry);
|
entries.push_back(entry);
|
||||||
|
|
||||||
for (transactions_list::const_iterator i = entry->transactions.begin();
|
for (transactions_list::const_iterator i = entry->transactions.begin();
|
||||||
|
|
@ -439,6 +531,9 @@ entry_t * journal_t::derive_entry(strings_list::iterator i,
|
||||||
}
|
}
|
||||||
|
|
||||||
done:
|
done:
|
||||||
|
if (! run_hooks(entry_finalize_hooks, *added))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
return added.release();
|
return added.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -590,6 +685,27 @@ account_t * py_find_account_2(journal_t& journal, const std::string& name,
|
||||||
return journal.find_account(name, auto_create);
|
return journal.find_account(name, auto_create);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
|
||||||
|
void py_add_entry_finalize_hook(journal_t& journal, object x)
|
||||||
|
{
|
||||||
|
add_hook(journal.entry_finalize_hooks,
|
||||||
|
extract<journal_t::entry_finalize_hook_t>(x));
|
||||||
|
}
|
||||||
|
|
||||||
|
void py_remove_entry_finalize_hook(journal_t& journal, object x)
|
||||||
|
{
|
||||||
|
remove_hook(journal.entry_finalize_hooks,
|
||||||
|
extract<journal_t::entry_finalize_hook_t>(x));
|
||||||
|
}
|
||||||
|
|
||||||
|
void py_run_entry_finalize_hooks(journal_t& journal, entry_t& entry)
|
||||||
|
{
|
||||||
|
run_hooks(journal.entry_finalize_hooks, entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
#define EXC_TRANSLATOR(type) \
|
#define EXC_TRANSLATOR(type) \
|
||||||
void exc_translate_ ## type(const type& err) { \
|
void exc_translate_ ## type(const type& err) { \
|
||||||
PyErr_SetString(PyExc_RuntimeError, err.what()); \
|
PyErr_SetString(PyExc_RuntimeError, err.what()); \
|
||||||
|
|
@ -677,6 +793,11 @@ void export_journal()
|
||||||
|
|
||||||
.def("add_entry", &journal_t::add_entry)
|
.def("add_entry", &journal_t::add_entry)
|
||||||
.def("remove_entry", &journal_t::remove_entry)
|
.def("remove_entry", &journal_t::remove_entry)
|
||||||
|
#if 0
|
||||||
|
.def("add_entry_finalize_hook", py_add_entry_finalize_hook)
|
||||||
|
.def("remove_entry_finalize_hook", py_remove_entry_finalize_hook)
|
||||||
|
.def("run_entry_finalize_hooks", py_run_entry_finalize_hooks)
|
||||||
|
#endif
|
||||||
.def("derive_entry", &journal_t::derive_entry,
|
.def("derive_entry", &journal_t::derive_entry,
|
||||||
return_value_policy<manage_new_object>())
|
return_value_policy<manage_new_object>())
|
||||||
|
|
||||||
|
|
|
||||||
20
ledger.el
20
ledger.el
|
|
@ -100,11 +100,10 @@
|
||||||
(if (time-less-p moment date)
|
(if (time-less-p moment date)
|
||||||
(throw 'found t)))))))
|
(throw 'found t)))))))
|
||||||
|
|
||||||
(defun ledger-add-entry (entry)
|
(defun ledger-add-entry (entry-text)
|
||||||
(interactive
|
(interactive
|
||||||
(list (read-string "Entry: " (format-time-string "%Y/%m/%d "))))
|
(list (read-string "Entry: " (format-time-string "%Y/%m/"))))
|
||||||
(let* ((args (mapcar 'shell-quote-argument (split-string entry)))
|
(let* ((date (car (split-string entry-text)))
|
||||||
(date (car args))
|
|
||||||
(insert-year t) exit-code)
|
(insert-year t) exit-code)
|
||||||
(if (string-match "\\([0-9]+\\)/\\([0-9]+\\)/\\([0-9]+\\)" date)
|
(if (string-match "\\([0-9]+\\)/\\([0-9]+\\)/\\([0-9]+\\)" date)
|
||||||
(setq date (encode-time 0 0 0 (string-to-int (match-string 3 date))
|
(setq date (encode-time 0 0 0 (string-to-int (match-string 3 date))
|
||||||
|
|
@ -117,7 +116,7 @@
|
||||||
(save-excursion
|
(save-excursion
|
||||||
(insert
|
(insert
|
||||||
(with-temp-buffer
|
(with-temp-buffer
|
||||||
(setq exit-code (apply 'ledger-run-ledger "entry" args))
|
(setq exit-code (ledger-run-ledger "entry" entry-text))
|
||||||
(if (= 0 exit-code)
|
(if (= 0 exit-code)
|
||||||
(progn
|
(progn
|
||||||
(goto-char (point-min))
|
(goto-char (point-min))
|
||||||
|
|
@ -125,8 +124,8 @@
|
||||||
(if insert-year
|
(if insert-year
|
||||||
(buffer-string)
|
(buffer-string)
|
||||||
(buffer-substring 5 (point-max))))
|
(buffer-substring 5 (point-max))))
|
||||||
(concat (if insert-year entry
|
(concat (if insert-year entry-text
|
||||||
(substring entry 5)) "\n"))) "\n"))))
|
(substring entry-text 5)) "\n"))) "\n"))))
|
||||||
|
|
||||||
(defun ledger-expand-entry ()
|
(defun ledger-expand-entry ()
|
||||||
(interactive)
|
(interactive)
|
||||||
|
|
@ -303,8 +302,11 @@
|
||||||
|
|
||||||
(defun ledger-run-ledger (&rest args)
|
(defun ledger-run-ledger (&rest args)
|
||||||
"run ledger with supplied arguments"
|
"run ledger with supplied arguments"
|
||||||
(apply 'call-process ledger-binary-path nil t nil
|
(let ((command (mapconcat 'identity
|
||||||
(append (list "-f" ledger-data-file) args)))
|
(append (list ledger-binary-path
|
||||||
|
"-f" ledger-data-file) args) " ")))
|
||||||
|
(insert (shell-command-to-string command)))
|
||||||
|
0)
|
||||||
|
|
||||||
(provide 'ledger)
|
(provide 'ledger)
|
||||||
|
|
||||||
|
|
|
||||||
31
ledger.h
31
ledger.h
|
|
@ -116,6 +116,8 @@ class entry_t
|
||||||
bool valid() const;
|
bool valid() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bool finalize_entry(entry_t& entry);
|
||||||
|
|
||||||
|
|
||||||
typedef std::map<const std::string, account_t *> accounts_map;
|
typedef std::map<const std::string, account_t *> accounts_map;
|
||||||
typedef std::pair<const std::string, account_t *> accounts_pair;
|
typedef std::pair<const std::string, account_t *> accounts_pair;
|
||||||
|
|
@ -181,6 +183,30 @@ class account_t
|
||||||
std::ostream& operator<<(std::ostream& out, const account_t& account);
|
std::ostream& operator<<(std::ostream& out, const account_t& account);
|
||||||
|
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void add_hook(std::list<T>& list, T func, const bool prepend = false) {
|
||||||
|
if (prepend)
|
||||||
|
list.push_front(func);
|
||||||
|
else
|
||||||
|
list.push_back(func);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void remove_hook(std::list<T>& list, T func) {
|
||||||
|
list.remove(func);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename Data>
|
||||||
|
bool run_hooks(std::list<T>& list, Data& entry) {
|
||||||
|
for (typename std::list<T>::const_iterator i = list.begin();
|
||||||
|
i != list.end();
|
||||||
|
i++)
|
||||||
|
if (! (*i)(entry))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
typedef std::list<entry_t *> entries_list;
|
typedef std::list<entry_t *> entries_list;
|
||||||
typedef std::list<std::string> strings_list;
|
typedef std::list<std::string> strings_list;
|
||||||
|
|
||||||
|
|
@ -195,9 +221,14 @@ class journal_t
|
||||||
|
|
||||||
mutable accounts_map accounts_cache;
|
mutable accounts_map accounts_cache;
|
||||||
|
|
||||||
|
typedef bool (*entry_finalize_hook_t)(entry_t& entry);
|
||||||
|
|
||||||
|
std::list<entry_finalize_hook_t> entry_finalize_hooks;
|
||||||
|
|
||||||
journal_t() {
|
journal_t() {
|
||||||
master = new account_t(NULL, "");
|
master = new account_t(NULL, "");
|
||||||
item_pool = item_pool_end = NULL;
|
item_pool = item_pool_end = NULL;
|
||||||
|
add_hook(entry_finalize_hooks, finalize_entry);
|
||||||
}
|
}
|
||||||
~journal_t();
|
~journal_t();
|
||||||
|
|
||||||
|
|
|
||||||
3
main.cc
3
main.cc
|
|
@ -164,6 +164,8 @@ int parse_and_report(int argc, char * argv[], char * envp[])
|
||||||
{
|
{
|
||||||
std::auto_ptr<journal_t> journal(new journal_t);
|
std::auto_ptr<journal_t> journal(new journal_t);
|
||||||
|
|
||||||
|
add_hook(journal->entry_finalize_hooks, handle_auto_xacts);
|
||||||
|
|
||||||
// Parse command-line arguments, and those set in the environment
|
// Parse command-line arguments, and those set in the environment
|
||||||
|
|
||||||
TIMER_START(process_opts);
|
TIMER_START(process_opts);
|
||||||
|
|
@ -224,7 +226,6 @@ int parse_and_report(int argc, char * argv[], char * envp[])
|
||||||
#endif
|
#endif
|
||||||
std::auto_ptr<qif_parser_t> qif_parser(new qif_parser_t);
|
std::auto_ptr<qif_parser_t> qif_parser(new qif_parser_t);
|
||||||
std::auto_ptr<textual_parser_t> text_parser(new textual_parser_t);
|
std::auto_ptr<textual_parser_t> text_parser(new textual_parser_t);
|
||||||
text_parser->add_finalize_hook(handle_auto_xacts);
|
|
||||||
|
|
||||||
register_parser(bin_parser.get());
|
register_parser(bin_parser.get());
|
||||||
#ifdef READ_GNUCASH
|
#ifdef READ_GNUCASH
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ void export_walk();
|
||||||
void export_format();
|
void export_format();
|
||||||
void export_valexpr();
|
void export_valexpr();
|
||||||
void export_datetime();
|
void export_datetime();
|
||||||
|
void export_autoxact();
|
||||||
|
|
||||||
void initialize_ledger_for_python()
|
void initialize_ledger_for_python()
|
||||||
{
|
{
|
||||||
|
|
@ -48,6 +49,7 @@ void initialize_ledger_for_python()
|
||||||
export_format();
|
export_format();
|
||||||
export_valexpr();
|
export_valexpr();
|
||||||
export_datetime();
|
export_datetime();
|
||||||
|
export_autoxact();
|
||||||
|
|
||||||
module_initialized = true;
|
module_initialized = true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
102
textual.cc
102
textual.cc
|
|
@ -145,93 +145,6 @@ void parse_automated_transactions(std::istream& in,
|
||||||
add_automated_transaction(new automated_transaction_t(line + 1, xacts));
|
add_automated_transaction(new automated_transaction_t(line + 1, xacts));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool finalize_entry(entry_t * entry)
|
|
||||||
{
|
|
||||||
// Scan through and compute the total balance for the entry. This
|
|
||||||
// is used for auto-calculating the value of entries with no cost,
|
|
||||||
// and the per-unit price of unpriced commodities.
|
|
||||||
|
|
||||||
value_t balance;
|
|
||||||
|
|
||||||
bool no_amounts = true;
|
|
||||||
for (transactions_list::const_iterator x = entry->transactions.begin();
|
|
||||||
x != entry->transactions.end();
|
|
||||||
x++)
|
|
||||||
if (! ((*x)->flags & TRANSACTION_VIRTUAL) ||
|
|
||||||
((*x)->flags & TRANSACTION_BALANCE)) {
|
|
||||||
amount_t * p = (*x)->cost ? (*x)->cost : &(*x)->amount;
|
|
||||||
if (*p) {
|
|
||||||
if (no_amounts) {
|
|
||||||
balance = *p;
|
|
||||||
no_amounts = false;
|
|
||||||
} else {
|
|
||||||
balance += *p;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If it's a null entry, then let the user have their fun
|
|
||||||
if (no_amounts)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
// If one transaction of a two-line transaction is of a different
|
|
||||||
// commodity than the others, and it has no per-unit price,
|
|
||||||
// determine its price by dividing the unit count into the value of
|
|
||||||
// the balance. This is done for the last eligible commodity.
|
|
||||||
|
|
||||||
if (balance.type == value_t::BALANCE &&
|
|
||||||
((balance_t *) balance.data)->amounts.size() == 2)
|
|
||||||
for (transactions_list::const_iterator x = entry->transactions.begin();
|
|
||||||
x != entry->transactions.end();
|
|
||||||
x++) {
|
|
||||||
if ((*x)->cost || ((*x)->flags & TRANSACTION_VIRTUAL))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
for (amounts_map::const_iterator i
|
|
||||||
= ((balance_t *) balance.data)->amounts.begin();
|
|
||||||
i != ((balance_t *) balance.data)->amounts.end();
|
|
||||||
i++)
|
|
||||||
if ((*i).second.commodity() != (*x)->amount.commodity()) {
|
|
||||||
assert((*x)->amount);
|
|
||||||
balance -= (*x)->amount;
|
|
||||||
assert(! (*x)->cost);
|
|
||||||
(*x)->cost = new amount_t(- (*i).second);
|
|
||||||
balance += *(*x)->cost;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Walk through each of the transactions, fixing up any that we
|
|
||||||
// can, and performing any on-the-fly calculations.
|
|
||||||
|
|
||||||
bool empty_allowed = true;
|
|
||||||
|
|
||||||
for (transactions_list::const_iterator x = entry->transactions.begin();
|
|
||||||
x != entry->transactions.end();
|
|
||||||
x++) {
|
|
||||||
if ((*x)->amount || ((*x)->flags & TRANSACTION_VIRTUAL))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (! empty_allowed || ! balance || balance.type != value_t::AMOUNT)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
empty_allowed = false;
|
|
||||||
|
|
||||||
// If one transaction gives no value at all -- and all the
|
|
||||||
// rest are of the same commodity -- then its value is the
|
|
||||||
// inverse of the computed value of the others.
|
|
||||||
|
|
||||||
(*x)->amount = *((amount_t *) balance.data);
|
|
||||||
(*x)->amount.negate();
|
|
||||||
|
|
||||||
balance = 0U;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ! balance;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
TIMER_DEF(entry_finish, "finalizing entry");
|
TIMER_DEF(entry_finish, "finalizing entry");
|
||||||
TIMER_DEF(entry_xacts, "parsing transactions");
|
TIMER_DEF(entry_xacts, "parsing transactions");
|
||||||
|
|
@ -294,17 +207,6 @@ entry_t * parse_entry(std::istream& in, account_t * master,
|
||||||
|
|
||||||
TIMER_STOP(entry_xacts);
|
TIMER_STOP(entry_xacts);
|
||||||
|
|
||||||
// If there were no transactions, throw away the entry
|
|
||||||
|
|
||||||
TIMER_START(entry_finish);
|
|
||||||
|
|
||||||
if (curr->transactions.empty() ||
|
|
||||||
! parser.run_finalize_hooks(curr.get())) {
|
|
||||||
return NULL; // ~auto_ptr will delete curr
|
|
||||||
}
|
|
||||||
|
|
||||||
TIMER_STOP(entry_finish);
|
|
||||||
|
|
||||||
return curr.release();
|
return curr.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -423,10 +325,10 @@ unsigned int textual_parser_t::parse(std::istream& in,
|
||||||
= new transaction_t(last_account, amt, TRANSACTION_VIRTUAL);
|
= new transaction_t(last_account, amt, TRANSACTION_VIRTUAL);
|
||||||
curr->add_transaction(xact);
|
curr->add_transaction(xact);
|
||||||
|
|
||||||
if (! run_finalize_hooks(curr.get()) ||
|
if (! journal->add_entry(curr.release()))
|
||||||
! journal->add_entry(curr.release()))
|
|
||||||
throw parse_error(path, linenum,
|
throw parse_error(path, linenum,
|
||||||
"Failed to record 'out' timelog entry");
|
"Failed to record 'out' timelog entry");
|
||||||
|
|
||||||
count++;
|
count++;
|
||||||
} else {
|
} else {
|
||||||
throw parse_error(path, linenum, "Cannot parse timelog entry date");
|
throw parse_error(path, linenum, "Cannot parse timelog entry date");
|
||||||
|
|
|
||||||
29
textual.h
29
textual.h
|
|
@ -5,42 +5,13 @@
|
||||||
|
|
||||||
namespace ledger {
|
namespace ledger {
|
||||||
|
|
||||||
bool finalize_entry(entry_t * entry);
|
|
||||||
|
|
||||||
class textual_parser_t : public parser_t
|
class textual_parser_t : public parser_t
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef bool (*finalize_hook_t)(entry_t * entry);
|
|
||||||
|
|
||||||
std::list<finalize_hook_t> finalize_hooks;
|
|
||||||
|
|
||||||
textual_parser_t() {
|
|
||||||
add_finalize_hook(finalize_entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual bool test(std::istream& in) const {
|
virtual bool test(std::istream& in) const {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void add_finalize_hook(finalize_hook_t func, bool prepend = false) {
|
|
||||||
if (prepend)
|
|
||||||
finalize_hooks.push_front(func);
|
|
||||||
else
|
|
||||||
finalize_hooks.push_back(func);
|
|
||||||
}
|
|
||||||
void remove_finalize_hook(finalize_hook_t func) {
|
|
||||||
finalize_hooks.remove(func);
|
|
||||||
}
|
|
||||||
bool run_finalize_hooks(entry_t * entry) {
|
|
||||||
for (std::list<finalize_hook_t>::const_iterator i
|
|
||||||
= finalize_hooks.begin();
|
|
||||||
i != finalize_hooks.end();
|
|
||||||
i++)
|
|
||||||
if (! (*i)(entry))
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual unsigned int parse(std::istream& in,
|
virtual unsigned int parse(std::istream& in,
|
||||||
journal_t * journal,
|
journal_t * journal,
|
||||||
account_t * master = NULL,
|
account_t * master = NULL,
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue