summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile3
-rw-r--r--amount.cc20
-rw-r--r--balance.cc21
-rw-r--r--equity.cc73
-rw-r--r--ledger.cc4
-rw-r--r--ledger.h5
-rw-r--r--ledger.texi4
-rw-r--r--main.cc53
-rw-r--r--parse.cc15
-rwxr-xr-xreport1
10 files changed, 151 insertions, 48 deletions
diff --git a/Makefile b/Makefile
index fb139113..de1c0fc1 100644
--- a/Makefile
+++ b/Makefile
@@ -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
diff --git a/amount.cc b/amount.cc
index 2d8271be..4caac14d 100644
--- a/amount.cc
+++ b/amount.cc
@@ -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;
diff --git a/balance.cc b/balance.cc
index 39b1e949..b9898a37 100644
--- a/balance.cc
+++ b/balance.cc
@@ -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
diff --git a/ledger.cc b/ledger.cc
index 44a0830e..1b354f12 100644
--- a/ledger.cc
+++ b/ledger.cc
@@ -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;
diff --git a/ledger.h b/ledger.h
index 0df8b870..d3f6de12 100644
--- a/ledger.h
+++ b/ledger.h
@@ -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
diff --git a/main.cc b/main.cc
index 7f3aa748..1b2884ec 100644
--- a/main.cc
+++ b/main.cc
@@ -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.
diff --git a/parse.cc b/parse.cc
index 07d7f6ce..8ff5207a 100644
--- a/parse.cc
+++ b/parse.cc
@@ -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
diff --git a/report b/report
index 949ccc3e..5f53b737 100755
--- a/report
+++ b/report
@@ -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