summaryrefslogtreecommitdiff
path: root/balance.cc
diff options
context:
space:
mode:
Diffstat (limited to 'balance.cc')
-rw-r--r--balance.cc196
1 files changed, 121 insertions, 75 deletions
diff --git a/balance.cc b/balance.cc
index b3ecf593..fd09bae1 100644
--- a/balance.cc
+++ b/balance.cc
@@ -1,10 +1,7 @@
-#include <iostream>
-#include <vector>
+#include "ledger.h"
#include <pcre.h> // Perl regular expression library
-#include "ledger.h"
-
namespace ledger {
//////////////////////////////////////////////////////////////////////
@@ -12,10 +9,38 @@ namespace ledger {
// Balance report.
//
-void report_balances(std::ostream& out, std::vector<entry *>& ledger,
- bool show_children, bool show_empty)
+static inline bool matches(const std::list<pcre *>& regexps,
+ const std::string& str) {
+ for (std::list<pcre *>::const_iterator r = regexps.begin();
+ r != regexps.end();
+ r++) {
+ int ovec[3];
+ if (pcre_exec(*r, NULL, str.c_str(), str.length(), 0, 0, ovec, 3) >= 0)
+ return true;
+ }
+
+ return false;
+}
+
+void report_balances(int argc, char *argv[], std::ostream& out)
{
-#if 0
+ bool show_current = false;
+ bool show_cleared = false;
+ bool show_children = false;
+ bool show_empty = false;
+ bool no_subtotals = false;
+
+ int c;
+ while (-1 != (c = getopt(argc, argv, "cCsSn"))) {
+ switch (char(c)) {
+ case 'c': show_current = true; break;
+ case 'C': show_cleared = true; break;
+ case 's': show_children = true; break;
+ case 'S': show_empty = true; break;
+ case 'n': no_subtotals = true; break;
+ }
+ }
+
// Compile the list of specified regular expressions, which can be
// specified on the command line, or using an include/exclude file.
@@ -26,97 +51,118 @@ void report_balances(std::ostream& out, std::vector<entry *>& ledger,
int erroffset;
pcre * re = pcre_compile(argv[optind], PCRE_CASELESS,
&error, &erroffset, NULL);
- assert(re);
- regexps.push_back(re);
+ if (! re)
+ std::cerr << "Warning: Failed to compile regexp: " << argv[optind]
+ << std::endl;
+ else
+ regexps.push_back(re);
}
-#endif
- // The balance of all accounts must equal zero
- totals future_balance;
- totals current_balance;
- totals cleared_balance;
+ // Walk through all of the ledger entries, computing the account
+ // totals
+
+ std::map<account *, totals *> balances;
+
+ std::time_t now = std::time(NULL);
+
+ for (ledger_iterator i = ledger.begin(); i != ledger.end(); i++) {
+ for (std::list<transaction *>::iterator x = (*i)->xacts.begin();
+ x != (*i)->xacts.end();
+ x++) {
+ account * acct = (*x)->acct;
+ if (! regexps.empty() && ! matches(regexps, acct->name))
+ continue;
+
+ while (acct) {
+ totals * balance = NULL;
+
+ std::map<account *, totals *>::iterator t = balances.find(acct);
+ if (t == balances.end()) {
+ balance = new totals;
+ balances.insert(std::pair<account *, totals *>(acct, balance));
+ } else {
+ balance = (*t).second;
+ }
+
+ if (show_current) {
+ if (difftime((*i)->date, now) < 0)
+ balance->credit((*x)->cost);
+ }
+ else if (show_cleared) {
+ if ((*i)->cleared)
+ balance->credit((*x)->cost);
+ }
+ else {
+ balance->credit((*x)->cost);
+ }
+
+ if (no_subtotals)
+ acct = NULL;
+ else
+ acct = acct->parent;
+ }
+ }
+ }
+
+ // Print out the balance report header
+
+ std::string which = "Future";
+ if (show_current)
+ which = "Current";
+ else if (show_cleared)
+ which = "Cleared";
std::cout.width(10);
- std::cout << std::right << "Future" << " ";
- std::cout.width(10);
- std::cout << std::right << "Current" << " ";
- std::cout.width(10);
- std::cout << std::right << "Cleared" << std::endl;
+ std::cout << std::right << which << std::endl;
- for (accounts_iterator i = accounts.begin();
- i != accounts.end();
- i++) {
- if (! show_empty && ! (*i).second->future)
+ // Walk through the accounts, given the balance report for each
+
+ totals total_balance;
+
+ for (accounts_iterator i = accounts.begin(); i != accounts.end(); i++) {
+ account * acct = (*i).second;
+
+ if (! regexps.empty() && ! matches(regexps, acct->name))
continue;
int depth = 0;
- account * acct = (*i).second;
- while (acct->parent) {
+ for (account * a = acct; a; a = a->parent)
depth++;
- acct = acct->parent;
- }
-#if 0
- if (! regexps.empty()) {
- bool matches = false;
- for (std::list<pcre *>::iterator r = regexps.begin();
- r != regexps.end();
- r++) {
- int ovector[30];
- if (pcre_exec(*r, NULL, (*i).first.c_str(), (*i).first.length(),
- 0, 0, ovector, 30) >= 0) {
- matches = true;
- break;
- }
- }
+ if (! show_children && depth)
+ continue;
- if (! matches)
- continue;
- }
- else
-#endif
- if (! show_children && depth) {
+ totals * balance = balances[acct];
+
+ if (! show_empty && ! *balance)
continue;
- }
std::cout.width(10);
- std::cout << (*i).second->future << " ";
- std::cout.width(10);
- std::cout << (*i).second->current << " ";
- std::cout.width(10);
- std::cout << (*i).second->cleared << " ";
+ std::cout << *balance << " ";
+
+ total_balance.credit(*balance);
if (depth) {
while (--depth >= 0)
std::cout << " ";
- std::cout << (*i).second->name << std::endl;
+ std::cout << acct->name << std::endl;
} else {
- std::cout << (*i).first << std::endl;
-
-#if 0
- if (regexps.empty()) {
-#endif
- future_balance.credit((*i).second->future);
- current_balance.credit((*i).second->current);
- cleared_balance.credit((*i).second->cleared);
-#if 0
- }
-#endif
+ std::cout << *acct << std::endl;
}
}
-#if 0
- if (regexps.empty()) {
-#endif
- std::cout.width(10);
- std::cout << std::right << future_balance << " ";
- std::cout.width(10);
- std::cout << std::right << current_balance << " ";
- std::cout.width(10);
- std::cout << std::right << cleared_balance << std::endl;
-#if 0
+ // Print the total of all the balances shown
+
+ std::cout.width(10);
+ std::cout << std::right << total_balance << std::endl;
+
+ // Free up temporary variables created on the heap
+
+ for (std::map<account *, totals *>::iterator i = balances.begin();
+ i != balances.end();
+ i++) {
+ delete (*i).second;
}
-#endif
}
} // namespace ledger