diff options
-rw-r--r-- | Makefile | 3 | ||||
-rw-r--r-- | amount.cc | 20 | ||||
-rw-r--r-- | balance.cc | 21 | ||||
-rw-r--r-- | equity.cc | 73 | ||||
-rw-r--r-- | ledger.cc | 4 | ||||
-rw-r--r-- | ledger.h | 5 | ||||
-rw-r--r-- | ledger.texi | 4 | ||||
-rw-r--r-- | main.cc | 53 | ||||
-rw-r--r-- | parse.cc | 15 | ||||
-rwxr-xr-x | report | 1 |
10 files changed, 151 insertions, 48 deletions
@@ -2,7 +2,8 @@ define GNUCASH true endef -CODE = amount.cc ledger.cc parse.cc balance.cc register.cc main.cc +CODE = amount.cc ledger.cc parse.cc \ + balance.cc register.cc equity.cc main.cc ifdef GNUCASH CODE := $(CODE) gnucash.cc endif @@ -51,6 +51,7 @@ class gmp_amount : public amount virtual amount * copy() const; virtual amount * value(amount *) const; + virtual amount * street() const; virtual operator bool() const; @@ -216,6 +217,25 @@ amount * gmp_amount::value(amount * pr) const } } +amount * gmp_amount::street() const +{ + amount * cost = NULL; + const amount * amt = this; + + for (int cycles = 0; cycles < 10; cycles++) { + totals::iterator pi = main_ledger.prices.amounts.find(amt->comm_symbol()); + if (pi == main_ledger.prices.amounts.end()) { + break; + } else { + amount * temp = cost; + amt = cost = amt->value((*pi).second); + if (temp) + delete temp; + } + } + return cost ? cost : copy(); +} + gmp_amount::operator bool() const { mpz_t copy; @@ -151,26 +151,7 @@ void report_balances(int argc, char **argv, std::ostream& out) if (! do_credit) continue; - amount * cost = (*x)->cost; - - bool allocated = false; - for (int cycles = 0; cost && cycles < 10; cycles++) { - std::map<const std::string, amount *>::iterator pi - = main_ledger.prices.amounts.find(cost->comm_symbol()); - - if (pi == main_ledger.prices.amounts.end()) { - balance->credit(cost); - if (allocated) - delete cost; - break; - } else { - amount * temp = cost; - cost = temp->value((*pi).second); - if (allocated) - delete temp; - allocated = true; - } - } + balance->credit((*x)->cost->street()); } } } diff --git a/equity.cc b/equity.cc new file mode 100644 index 00000000..3b80f166 --- /dev/null +++ b/equity.cc @@ -0,0 +1,73 @@ +#include "ledger.h" + +namespace ledger { + +static void equity_entry(std::ostream& out, const account * acct, + const std::list<mask>& regexps) +{ + if (acct->balance && + (regexps.empty() || matches(regexps, acct->as_str()))) { + entry opening; + + opening.date = std::time(NULL); + opening.cleared = true; + opening.desc = "Opening Balance"; + + transaction * xact; + for (totals::const_iterator i = acct->balance.amounts.begin(); + i != acct->balance.amounts.end(); + i++) { + if (! *((*i).second)) // skip if zero balance for the commodity + continue; + + xact = new transaction(); + xact->acct = const_cast<account *>(acct); + xact->cost = (*i).second->street(); + opening.xacts.push_back(xact); + + xact = new transaction(); + xact->acct = main_ledger.find_account("Equity:Opening Balances"); + xact->cost = (*i).second->street(); + xact->cost->negate(); + opening.xacts.push_back(xact); + } + + opening.print(out); + } + + // Display balances for all child accounts + + for (account::const_iterator i = acct->children.begin(); + i != acct->children.end(); + i++) + equity_entry(out, (*i).second, regexps); +} + +////////////////////////////////////////////////////////////////////// +// +// Create an Equity file based on a ledger. This is used for +// archiving past years, and starting out a new year with compiled +// balances. +// + +void equity_ledger(int argc, char **argv, std::ostream& out) +{ + optind = 1; + + // Compile the list of specified regular expressions, which can be + // specified on the command line, or using an include/exclude file + + for (; optind < argc; optind++) + record_regexp(argv[optind], regexps); + + // The account have their current totals already generated as a + // result of parsing. We just have to output those values. + // totals + + for (accounts_iterator i = main_ledger.accounts.begin(); + i != main_ledger.accounts.end(); + i++) + equity_entry(out, (*i).second, regexps); +} + +} // namespace ledger @@ -133,14 +133,14 @@ void totals::print(std::ostream& out, int width) const } } -amount * totals::value(const std::string& commodity) +amount * totals::value(const std::string& commodity) const { // Render all of the amounts into the given commodity. This // requires known prices for each commodity. amount * total = create_amount((commodity + " 0.00").c_str()); - for (iterator i = amounts.begin(); i != amounts.end(); i++) + for (const_iterator i = amounts.begin(); i != amounts.end(); i++) *total += *((*i).second); return total; @@ -1,5 +1,5 @@ #ifndef _LEDGER_H -#define _LEDGER_H "$Revision: 1.8 $" +#define _LEDGER_H "$Revision: 1.9 $" ////////////////////////////////////////////////////////////////////// // @@ -117,6 +117,7 @@ class amount virtual const std::string& comm_symbol() const = 0; virtual amount * copy() const = 0; virtual amount * value(amount * pr = NULL) const = 0; + virtual amount * street() const = 0; // Test if non-zero @@ -235,7 +236,7 @@ struct totals void print(std::ostream& out, int width) const; // Returns an allocated entity - amount * value(const std::string& comm); + amount * value(const std::string& comm) const; amount * sum(const std::string& comm) { return amounts[comm]; } diff --git a/ledger.texi b/ledger.texi index f716a448..cb180eb0 100644 --- a/ledger.texi +++ b/ledger.texi @@ -1,5 +1,5 @@ \input texinfo @c -*-texinfo-*- -@comment $Id: ledger.texi,v 1.3 2003/09/30 23:17:18 johnw Exp $ +@comment $Id: ledger.texi,v 1.4 2003/10/01 04:42:13 johnw Exp $ @comment %**start of header @setfilename ledger.info @@ -274,7 +274,7 @@ currently $357 per ounce, then each dollar is worth 1/357 AU: $5000 would buy 14 ounces of gold, which becomes the new display commodity since a conversion factor was provided. -Commodities conversions can also be chained, up to a depth of 15. +Commodities conversions can also be chained, up to a depth of 10. Here is a sample prices database that uses chaining: @example @@ -9,6 +9,7 @@ namespace ledger { extern void report_balances(int argc, char **argv, std::ostream& out); extern void print_register(int argc, char **argv, std::ostream& out); extern void print_ledger(int argc, char *argv[], std::ostream& out); + extern void equity_ledger(int argc, char **argv, std::ostream& out); bool show_cleared; @@ -39,6 +40,11 @@ void show_help(std::ostream& out) int main(int argc, char *argv[]) { + // Global defaults + + commodity * usd = new commodity("$", true, false, true, false, 2); + main_ledger.commodities.insert(commodities_entry("USD", usd)); + // Parse the command-line options std::istream * file = NULL; @@ -114,18 +120,34 @@ int main(int argc, char *argv[]) } if (optind == argc) { - std::cerr << "usage: ledger [options] COMMAND [options] [ARGS]" << std::endl - << std::endl - << "ledger options:" << std::endl - << " -f FILE specify pathname of ledger data file" << std::endl - << std::endl - << "commands:" << std::endl - << " balance show balance totals" << std::endl - << " print print all ledger entries" << std::endl - << std::endl - << "`balance' command options:" << std::endl - << " -s show sub-accounts in balance totals" << std::endl - << " -S show empty accounts in balance totals" << std::endl; + std::cerr + << "usage: ledger [options] COMMAND [options] [REGEXPS]" << std::endl + << std::endl + << "ledger options:" << std::endl + << " -C also show cleared transactions" << std::endl + << " -b DATE specify a beginning date" << std::endl + << " -c do not show future entries (same as -e TODAY)" << std::endl + << " -e DATE specify an ending date" << std::endl + << " -f FILE specify pathname of ledger data file" << std::endl + << " -h display this help text" << std::endl +#ifdef HUQUQULLAH + << " -H do not auto-compute Huququ'llah" << std::endl +#endif + << " -i FILE read the list of inclusion regexps from FILE" << std::endl + << " -p FILE read the list of prices from FILE" << std::endl + << " -w print out warnings where applicable" << std::endl + << std::endl + << "commands:" << std::endl + << " balance show balance totals" << std::endl + << " register display a register for ACCOUNT" << std::endl + << " print print all ledger entries" << std::endl + << " equity generate equity ledger for all entries" << std::endl + << std::endl + << "`balance' options:" << std::endl + << " -F print each account's full name" << std::endl + << " -n do not generate totals for parent accounts" << std::endl + << " -s show sub-accounts in balance totals" << std::endl + << " -S show empty accounts in balance totals" << std::endl; return 1; } @@ -137,11 +159,6 @@ int main(int argc, char *argv[]) return 1; } - // Global defaults - - commodity * usd = new commodity("$", true, false, true, false, 2); - main_ledger.commodities.insert(commodities_entry("USD", usd)); - // Read the command word const std::string command = argv[optind]; @@ -182,6 +199,8 @@ int main(int argc, char *argv[]) print_register(argc - optind, &argv[optind], std::cout); else if (command == "print") print_ledger(argc - optind, &argv[optind], std::cout); + else if (command == "equity") + equity_ledger(argc - optind, &argv[optind], std::cout); } // main.cc ends here. @@ -185,14 +185,14 @@ bool parse_ledger(std::istream& in) } #ifdef HUQUQULLAH - bool exempt = false; + bool exempt_or_necessary = false; if (compute_huquq) { if (*p == '!') { - exempt = true; + exempt_or_necessary = true; p++; } else if (matches(huquq_categories, p)) { - exempt = true; + exempt_or_necessary = true; } } #endif @@ -203,23 +203,30 @@ bool parse_ledger(std::istream& in) curr->xacts.push_back(xact); #ifdef HUQUQULLAH - if (exempt) { + if (exempt_or_necessary) { static amount * huquq = create_amount("H 1.00"); amount * temp; + // Reflect the exempt or necessary transaction in the + // Huququ'llah account, using the H commodity, which is 19% + // of whichever DEFAULT_COMMODITY ledger was compiled with. transaction * t = new transaction(); t->acct = main_ledger.find_account("Huququ'llah"); temp = xact->cost->value(); t->cost = temp->value(huquq); delete temp; + t->acct->balance.credit(t->cost); curr->xacts.push_back(t); + // Balance the above transaction by recording the inverse in + // Expenses:Huququ'llah. t = new transaction(); t->acct = main_ledger.find_account("Expenses:Huququ'llah"); temp = xact->cost->value(); t->cost = temp->value(huquq); delete temp; t->cost->negate(); + t->acct->balance.credit(t->cost); curr->xacts.push_back(t); } #endif @@ -16,4 +16,5 @@ case "$command" in health supplies -insurance -vacation ;; huquq) $line "$@" balance ^huquq ;; gold) $line "$@" balance -G $1 ^huquq ;; + equity) $line "$@" equity -- -^Income -^Expenses -^Equity ;; esac |