diff options
Diffstat (limited to 'balance.cc')
-rw-r--r-- | balance.cc | 165 |
1 files changed, 116 insertions, 49 deletions
@@ -1,14 +1,11 @@ #include "ledger.h" +#include <fstream> +#include <unistd.h> #include <pcre.h> // Perl regular expression library namespace ledger { -////////////////////////////////////////////////////////////////////// -// -// Balance report. -// - static bool show_current = false; static bool show_cleared = false; static bool show_children = false; @@ -24,10 +21,14 @@ struct mask }; static inline bool matches(const std::list<mask>& regexps, - const std::string& str) { - // If the first pattern is an exclude, then we assume that all - // patterns match if they don't match the exclude. + const std::string& str) +{ + // If the first pattern is an exclude, we assume all patterns match + // if they don't match the exclude. If the first pattern is an + // include, then only accounts matching the include will match. + bool match = (*regexps.begin()).exclude; + for (std::list<mask>::const_iterator r = regexps.begin(); r != regexps.end(); r++) { @@ -36,6 +37,7 @@ static inline bool matches(const std::list<mask>& regexps, 0, 0, ovec, 3) >= 0) match = ! (*r).exclude; } + return match; } @@ -82,48 +84,113 @@ static void display_total(std::ostream& out, totals& total_balance, } } + // Display balances for all child accounts + for (account::const_iterator i = acct->children.begin(); i != acct->children.end(); i++) display_total(out, total_balance, (*i).second, balances, regexps); } +static void record_price(char * setting, + std::map<const std::string, amount *>& prices) +{ + char * c = setting; + char * p = std::strchr(setting, '='); + if (! p) { + std::cerr << "Warning: Invalid price setting: " << setting << std::endl; + } else { + *p++ = '\0'; + amount * price = create_amount(p); + prices.insert(std::pair<const std::string, amount *>(c, price)); + } +} + +static void record_regexp(char * pattern, std::list<mask>& regexps) +{ + bool exclude = false; + + char * pat = pattern; + if (*pat == '-') { + exclude = true; + pat++; + while (std::isspace(*pat)) + pat++; + } + else if (*pat == '+') { + pat++; + while (std::isspace(*pat)) + pat++; + } + + const char *error; + int erroffset; + pcre * re = pcre_compile(pat, PCRE_CASELESS, &error, &erroffset, NULL); + if (! re) + std::cerr << "Warning: Failed to compile regexp: " << pattern + << std::endl; + else + regexps.push_back(mask(exclude, re)); +} + +////////////////////////////////////////////////////////////////////// +// +// Balance reporting code +// + void report_balances(int argc, char **argv, std::ostream& out) { + std::map<const std::string, amount *> prices; + std::list<mask> regexps; + int c; optind = 1; - while (-1 != (c = getopt(argc, argv, "cCsSn"))) { + while (-1 != (c = getopt(argc, argv, "cCsSni:p:"))) { 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; + + // -i path-to-file-of-regexps + case 'i': + if (access(optarg, R_OK) != -1) { + std::ifstream include(optarg); + + while (! include.eof()) { + char buf[80]; + include.getline(buf, 79); + if (*buf && ! std::isspace(*buf)) + record_regexp(buf, regexps); + } + } + break; + + // -p "COMMODITY=PRICE" + // -p path-to-price-database + case 'p': + if (access(optarg, R_OK) != -1) { + std::ifstream pricedb(optarg); + + while (! pricedb.eof()) { + char buf[80]; + pricedb.getline(buf, 79); + if (*buf && ! std::isspace(*buf)) + record_price(buf, prices); + } + } else { + record_price(optarg, prices); + } + break; } } // Compile the list of specified regular expressions, which can be - // specified on the command line, or using an include/exclude file. + // specified on the command line, or using an include/exclude file - std::list<mask> regexps; - - for (; optind < argc; optind++) { - bool exclude = false; - char * pat = argv[optind]; - if (*pat == '-') { - exclude = true; - pat++; - } - - const char *error; - int erroffset; - pcre * re = pcre_compile(pat, PCRE_CASELESS, &error, &erroffset, NULL); - if (! re) - std::cerr << "Warning: Failed to compile regexp: " << argv[optind] - << std::endl; - else - regexps.push_back(mask(exclude, re)); - } + for (; optind < argc; optind++) + record_regexp(argv[optind], regexps); // Walk through all of the ledger entries, computing the account // totals @@ -165,34 +232,30 @@ void report_balances(int argc, char **argv, std::ostream& out) do_credit = true; } - if (do_credit) + if (! do_credit) + continue; + + std::map<const std::string, amount *>::iterator pi + = prices.find((*x)->cost->comm_symbol()); + + if (pi == prices.end()) { balance->credit((*x)->cost); + } else { + amount * value = (*x)->cost->value((*pi).second); + balance->credit(value); + delete value; + } } } } -#if 0 - // Print out the balance report header - - std::string which = "Future"; - if (show_current) - which = "Current"; - else if (show_cleared) - which = "Cleared"; - - out.width(20); - out << std::right << which << std::endl - << "--------------------" << std::endl; -#endif - - // Walk through all the top-level accounts, given the balance + // Walk through all the top-level accounts, giving the balance // report for each, and then for each of their children. totals total_balance; for (accounts_iterator i = accounts.begin(); i != accounts.end(); i++) - if (! (*i).second->parent) - display_total(out, total_balance, (*i).second, balances, regexps); + display_total(out, total_balance, (*i).second, balances, regexps); // Print the total of all the balances shown @@ -204,9 +267,13 @@ void report_balances(int argc, char **argv, std::ostream& out) for (std::map<account *, totals *>::iterator i = balances.begin(); i != balances.end(); - i++) { + i++) + delete (*i).second; + + for (std::map<const std::string, amount *>::iterator i = prices.begin(); + i != prices.end(); + i++) delete (*i).second; - } } } // namespace ledger |