summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Wiegley <johnw@newartisans.com>2003-10-05 00:22:17 +0000
committerJohn Wiegley <johnw@newartisans.com>2003-10-05 00:22:17 +0000
commit260217c8ab48c6000021222e0d1c989dce80b869 (patch)
tree74a76b2ab36ef99bf56be92b848544394e14a579
parent2c109226140a99a07af079c70e54fb396bb3484e (diff)
downloadfork-ledger-260217c8ab48c6000021222e0d1c989dce80b869.tar.gz
fork-ledger-260217c8ab48c6000021222e0d1c989dce80b869.tar.bz2
fork-ledger-260217c8ab48c6000021222e0d1c989dce80b869.zip
*** empty log message ***
-rw-r--r--amount.cc83
-rw-r--r--balance.cc3
-rw-r--r--equity.cc6
-rw-r--r--gnucash.cc14
-rw-r--r--ledger.cc31
-rw-r--r--ledger.h52
-rw-r--r--main.cc41
-rw-r--r--parse.cc65
-rw-r--r--register.cc11
9 files changed, 164 insertions, 142 deletions
diff --git a/amount.cc b/amount.cc
index 89c9d220..1c1155ff 100644
--- a/amount.cc
+++ b/amount.cc
@@ -45,17 +45,13 @@ class gmp_amount : public amount
mpz_clear(quantity);
}
- virtual commodity * comm() const {
+ virtual commodity * commdty() const {
return quantity_comm;
}
- virtual const std::string& comm_symbol() const {
- assert(quantity_comm);
- return quantity_comm->symbol;
- }
virtual amount * copy() const;
virtual amount * value(amount *) const;
- virtual amount * street() const;
+ virtual amount * street(bool get_quotes) const;
virtual bool has_price() const {
return priced;
}
@@ -199,54 +195,54 @@ amount * gmp_amount::value(amount * pr) const
}
}
-amount * gmp_amount::street() const
+static bool get_commodity_price(commodity * comm)
{
- amount * cost = NULL;
- const amount * amt = this;
+ using namespace std;
- extern bool get_quotes;
+ char buf[256];
+ buf[0] = '\0';
- 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()) {
- using namespace std;
+ if (FILE * fp = popen((std::string("getquote ") +
+ comm->symbol).c_str(), "r")) {
+ if (feof(fp) || ! fgets(buf , 255, fp)) {
+ fclose(fp);
+ return false;
+ }
+ fclose(fp);
+ }
- if (! get_quotes)
- break;
+ if (buf[0]) {
+ char * p = strchr(buf, '\n');
+ if (p) *p = '\0';
- char buf[256];
- buf[0] = '\0';
+ comm->price = create_amount(buf);
+ return true;
+ }
+ return false;
+}
- if (FILE * fp = popen((std::string("getquote ") +
- amt->comm_symbol()).c_str(), "r")) {
- if (feof(fp) || ! fgets(buf , 255, fp)) {
- fclose(fp);
- break;
- }
- fclose(fp);
- }
+amount * gmp_amount::street(bool get_quotes) const
+{
+ amount * amt = copy();
- if (buf[0]) {
- char * p = strchr(buf, '\n');
- if (p) *p = '\0';
+ int max = 10;
- main_ledger->record_price((amt->comm_symbol() + "=" + buf).c_str());
- continue;
- }
- break;
- } else {
- amount * temp = cost;
- amt = cost = amt->value((*pi).second);
-
- bool same = temp && temp->comm() == cost->comm();
- if (temp)
- delete temp;
- if (same)
+ while (--max >= 0) {
+ if (! amt->commdty()->price) {
+ if (get_quotes)
+ get_commodity_price(amt->commdty());
+ if (! amt->commdty()->price)
break;
}
+
+ amount * old = amt;
+ amt = amt->value(amt->commdty()->price);
+ delete old;
+
+ if (amt->commdty() == old->commdty())
+ break;
}
- return cost ? cost : copy();
+ return amt;
}
void gmp_amount::set_value(const amount * val)
@@ -551,7 +547,6 @@ static commodity * parse_amount(mpz_t out, const char * num,
}
commodity * comm = NULL;
-
if (saw_commodity) {
commodities_map_iterator item =
main_ledger->commodities.find(symbol.c_str());
diff --git a/balance.cc b/balance.cc
index 03063d21..0cf5305f 100644
--- a/balance.cc
+++ b/balance.cc
@@ -10,6 +10,7 @@ extern bool show_children;
extern bool show_empty;
extern bool show_subtotals;
extern bool full_names;
+extern bool get_quotes;
extern std::time_t begin_date;
extern bool have_beginning;
@@ -100,7 +101,7 @@ void report_balances(std::ostream& out, regexps_map& regexps)
}
if (acct->checked == 1)
- acct->balance.credit((*x)->cost->street());
+ acct->balance.credit((*x)->cost->street(get_quotes));
}
}
}
diff --git a/equity.cc b/equity.cc
index accbfd7c..2f3246aa 100644
--- a/equity.cc
+++ b/equity.cc
@@ -2,6 +2,8 @@
namespace ledger {
+extern bool get_quotes;
+
static void equity_entry(account * acct, regexps_map& regexps,
std::ostream& out)
{
@@ -23,12 +25,12 @@ static void equity_entry(account * acct, regexps_map& regexps,
xact = new transaction();
xact->acct = const_cast<account *>(acct);
- xact->cost = (*i).second->street();
+ xact->cost = (*i).second->street(get_quotes);
opening.xacts.push_back(xact);
xact = new transaction();
xact->acct = main_ledger->find_account("Equity:Opening Balances");
- xact->cost = (*i).second->street();
+ xact->cost = (*i).second->street(get_quotes);
xact->cost->negate();
opening.xacts.push_back(xact);
}
diff --git a/gnucash.cc b/gnucash.cc
index 234c869b..b29ea674 100644
--- a/gnucash.cc
+++ b/gnucash.cc
@@ -18,6 +18,7 @@ static amount * curr_value;
static std::string curr_quant;
static XML_Parser current_parser;
static accounts_map accounts_by_id;
+static bool do_compute;
static enum {
NO_ACTION,
@@ -197,7 +198,7 @@ static void dataHandler(void *userData, const char *s, int len)
std::string value = curr_quant + " " + xact->acct->comm->symbol;
- if (curr_value->comm() == xact->acct->comm) {
+ if (curr_value->commdty() == xact->acct->comm) {
// assert: value must be equal to curr_value.
delete curr_value;
curr_value = NULL;
@@ -207,7 +208,7 @@ static void dataHandler(void *userData, const char *s, int len)
if (curr_value)
delete curr_value;
- if (main_ledger->compute_balances)
+ if (do_compute)
xact->acct->balance.credit(xact->cost);
break;
}
@@ -227,15 +228,14 @@ static void dataHandler(void *userData, const char *s, int len)
}
}
-state * parse_gnucash(std::istream& in, bool compute_balances)
+book * parse_gnucash(std::istream& in, bool compute_balances)
{
char buf[BUFSIZ];
- state * ledger = new state;
-
- main_ledger = ledger;
- ledger->compute_balances = compute_balances;
+ book * ledger = new book;
+ main_ledger = ledger;
+ do_compute = compute_balances;
action = NO_ACTION;
curr_account = NULL;
curr_entry = NULL;
diff --git a/ledger.cc b/ledger.cc
index 7f546617..30ffacf9 100644
--- a/ledger.cc
+++ b/ledger.cc
@@ -5,7 +5,7 @@
namespace ledger {
bool use_warnings = false;
-state * main_ledger;
+book * main_ledger;
const std::string transaction::acct_as_str() const
{
@@ -67,9 +67,9 @@ void entry::print(std::ostream& out, bool shortcut) const
out << std::endl;
- if (shortcut &&
- (xacts.size() != 2 ||
- xacts.front()->cost->comm() != xacts.back()->cost->comm()))
+ if (shortcut && (xacts.size() != 2 ||
+ (xacts.front()->cost->commdty() !=
+ xacts.back()->cost->commdty())))
shortcut = false;
for (std::list<transaction *>::const_iterator x = xacts.begin();
@@ -172,7 +172,7 @@ void totals::print(std::ostream& out, int width) const
// Print out the entire ledger that was read in, sorted by date.
// This can be used to "wash" ugly ledger files.
-void state::print(std::ostream& out, regexps_map& regexps,
+void book::print(std::ostream& out, regexps_map& regexps,
bool shortcut) const
{
for (entries_list_const_iterator i = entries.begin();
@@ -251,7 +251,7 @@ bool matches(const regexps_map& regexps, const std::string& str,
return match;
}
-state::~state()
+book::~book()
{
for (commodities_map_iterator i = commodities.begin();
i != commodities.end();
@@ -269,24 +269,7 @@ state::~state()
delete *i;
}
-void state::record_price(const std::string& setting)
-{
- char buf[128];
- std::strcpy(buf, setting.c_str());
-
- assert(setting.length() < 128);
-
- char * c = buf;
- char * p = std::strchr(buf, '=');
- if (! p) {
- std::cerr << "Warning: Invalid price setting: " << setting << std::endl;
- } else {
- *p++ = '\0';
- prices.amounts.insert(totals::pair(c, create_amount(p)));
- }
-}
-
-account * state::find_account(const std::string& name, bool create)
+account * book::find_account(const std::string& name, bool create)
{
accounts_map_iterator i = accounts_cache.find(name);
if (i != accounts_cache.end())
diff --git a/ledger.h b/ledger.h
index 4b21b54f..4e75bfe0 100644
--- a/ledger.h
+++ b/ledger.h
@@ -1,5 +1,5 @@
#ifndef _LEDGER_H
-#define _LEDGER_H "$Revision: 1.19 $"
+#define _LEDGER_H "$Revision: 1.20 $"
//////////////////////////////////////////////////////////////////////
//
@@ -26,19 +26,22 @@
namespace ledger {
+struct amount;
struct commodity
{
std::string name;
std::string symbol;
- bool prefix;
- bool separate;
- bool thousands;
- bool european;
+ mutable amount * price; // the current price
- int precision;
+ bool prefix;
+ bool separate;
+ bool thousands;
+ bool european;
- commodity() : prefix(false), separate(true),
+ int precision;
+
+ commodity() : price(NULL), prefix(false), separate(true),
thousands(false), european(false) {}
commodity(const std::string& sym, bool pre = false, bool sep = true,
bool thou = true, bool euro = false, int prec = 2);
@@ -54,11 +57,10 @@ class amount
public:
virtual ~amount() {}
- virtual commodity * comm() const = 0;
- virtual const std::string& comm_symbol() const = 0;
+ virtual commodity * commdty() const = 0;
virtual amount * copy() const = 0;
virtual amount * value(amount * pr = NULL) const = 0;
- virtual amount * street() const = 0;
+ virtual amount * street(bool get_quotes) const = 0;
virtual bool has_price() const = 0;
virtual void set_value(const amount * pr) = 0;
@@ -88,6 +90,10 @@ struct mask
pcre * regexp;
mask(const std::string& pattern);
+
+ ~mask() {
+ pcre_free(regexp);
+ }
};
typedef std::list<mask> regexps_map;
@@ -169,10 +175,10 @@ typedef entries_list::const_iterator entries_list_const_iterator;
struct totals
{
- typedef std::map<const std::string, amount *> map;
- typedef map::iterator iterator;
- typedef map::const_iterator const_iterator;
- typedef std::pair<const std::string, amount *> pair;
+ typedef std::map<commodity *, amount *> map;
+ typedef map::iterator iterator;
+ typedef map::const_iterator const_iterator;
+ typedef std::pair<commodity *, amount *> pair;
map amounts;
@@ -180,9 +186,9 @@ struct totals
void credit(const amount * val) {
std::pair<iterator, bool> result =
- amounts.insert(pair(val->comm_symbol(), val->copy()));
+ amounts.insert(pair(val->commdty(), val->copy()));
if (! result.second)
- amounts[val->comm_symbol()]->credit(val);
+ amounts[val->commdty()]->credit(val);
}
void credit(const totals& other);
@@ -191,7 +197,7 @@ struct totals
void print(std::ostream& out, int width) const;
// Returns an allocated entity
- amount * sum(const std::string& comm) {
+ amount * sum(commodity * comm) {
return amounts[comm];
}
};
@@ -231,13 +237,12 @@ struct account
};
-struct state
+struct book
{
commodities_map commodities;
accounts_map accounts;
accounts_map accounts_cache; // maps full names to accounts
entries_list entries;
- totals prices;
int current_year;
typedef std::map<std::list<mask> *,
@@ -248,12 +253,9 @@ struct state
typedef virtual_map::const_iterator virtual_map_iterator;
- bool compute_balances;
virtual_map virtual_mapping;
- ~state();
-
- void record_price(const std::string& setting);
+ ~book();
template<typename Compare>
void sort(Compare comp) {
@@ -264,12 +266,12 @@ struct state
account * find_account(const std::string& name, bool create = true);
};
-extern state * main_ledger;
+extern book * main_ledger;
extern bool use_warnings;
inline commodity::commodity(const std::string& sym, bool pre, bool sep,
bool thou, bool euro, int prec)
- : symbol(sym), prefix(pre), separate(sep),
+ : symbol(sym), price(NULL), prefix(pre), separate(sep),
thousands(thou), european(euro), precision(prec) {
std::pair<commodities_map_iterator, bool> result =
main_ledger->commodities.insert(commodities_map_pair(sym, this));
diff --git a/main.cc b/main.cc
index 4258b72e..f5021acc 100644
--- a/main.cc
+++ b/main.cc
@@ -5,14 +5,15 @@
#include <fstream>
namespace ledger {
- extern state * parse_ledger(std::istream& in, regexps_map& regexps,
+ extern book * parse_ledger(std::istream& in, regexps_map& regexps,
bool compute_balances);
#ifdef READ_GNUCASH
- extern state * parse_gnucash(std::istream& in, bool compute_balances);
+ extern book * parse_gnucash(std::istream& in, bool compute_balances);
#endif
extern bool parse_date(const char * date_str, std::time_t * result,
const int year = -1);
+ extern void parse_price_setting(const std::string& setting);
extern void report_balances(std::ostream& out, regexps_map& regexps);
extern void print_register(const std::string& acct_name, std::ostream& out,
@@ -80,6 +81,7 @@ static void show_help(std::ostream& out)
int main(int argc, char * argv[])
{
std::istream * file = NULL;
+ std::string prices;
regexps_map regexps;
@@ -189,18 +191,7 @@ int main(int argc, char * argv[])
// -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))
- main_ledger->record_price(buf);
- }
- } else {
- main_ledger->record_price(optarg);
- }
+ prices = optarg;
break;
case 'P':
@@ -297,6 +288,22 @@ int main(int argc, char * argv[])
for (; optind < argc; optind++)
regexps.push_back(mask(argv[optind]));
+ // Record any prices specified by the user
+
+ if (! prices.empty()) {
+ if (access(prices.c_str(), R_OK) != -1) {
+ std::ifstream pricedb(prices.c_str());
+ while (! pricedb.eof()) {
+ char buf[80];
+ pricedb.getline(buf, 79);
+ if (*buf && ! std::isspace(*buf))
+ parse_price_setting(buf);
+ }
+ } else {
+ parse_price_setting(prices);
+ }
+ }
+
// Process the command
if (command == "balance") {
@@ -313,8 +320,10 @@ int main(int argc, char * argv[])
equity_ledger(std::cout, regexps);
}
-#if 0
- // Deleting the main ledger just isn't necessary at this point.
+#ifdef DEBUG
+ // Ordinarily, deleting the main ledger just isn't necessary at
+ // this point.
+
delete main_ledger;
#endif
}
diff --git a/parse.cc b/parse.cc
index 6a79eae8..146b93ea 100644
--- a/parse.cc
+++ b/parse.cc
@@ -84,11 +84,40 @@ bool parse_date(const char * date_str, std::time_t * result,
return false;
}
+void parse_price_setting(const std::string& setting)
+{
+ char buf[128];
+ std::strcpy(buf, setting.c_str());
+
+ assert(setting.length() < 128);
+
+ char * c = buf;
+ char * p = std::strchr(buf, '=');
+ if (! p) {
+ std::cerr << "Warning: Invalid price setting: " << setting << std::endl;
+ } else {
+ *p++ = '\0';
+
+ commodity * comm = NULL;
+
+ commodities_map_iterator item = main_ledger->commodities.find(c);
+ if (item == main_ledger->commodities.end()) {
+ comm = new commodity(c);
+ } else {
+ comm = (*item).second;
+ }
+
+ assert(comm);
+ comm->price = create_amount(p);
+ }
+}
+
#define MAX_LINE 1024
-static int linenum;
+static int linenum;
+static bool do_compute;
-transaction * parse_transaction(std::istream& in, state * ledger)
+transaction * parse_transaction(std::istream& in, book * ledger)
{
transaction * xact = new transaction();
@@ -148,13 +177,13 @@ transaction * parse_transaction(std::istream& in, state * ledger)
xact->acct = ledger->find_account(p);
- if (ledger->compute_balances && xact->cost)
+ if (do_compute && xact->cost)
xact->acct->balance.credit(xact->cost);
return xact;
}
-entry * parse_entry(std::istream& in, state * ledger)
+entry * parse_entry(std::istream& in, book * ledger)
{
entry * curr = new entry;
@@ -233,12 +262,12 @@ entry * parse_entry(std::istream& in, state * ledger)
continue;
if (! (*x)->cost->has_price() &&
- ! (*x)->cost->comm()->prefix &&
- (*x)->cost->comm()->separate) {
+ ! (*x)->cost->commdty()->prefix &&
+ (*x)->cost->commdty()->separate) {
for (totals::iterator i = balance.amounts.begin();
i != balance.amounts.end();
i++) {
- if ((*i).second->comm() != (*x)->cost->comm()) {
+ if ((*i).second->commdty() != (*x)->cost->commdty()) {
(*x)->cost->set_value((*i).second);
break;
}
@@ -276,7 +305,7 @@ entry * parse_entry(std::istream& in, state * ledger)
(*x)->cost = (*i).second->value();
(*x)->cost->negate();
- if (ledger->compute_balances)
+ if (do_compute)
(*x)->acct->balance.credit((*x)->cost);
}
@@ -284,7 +313,7 @@ entry * parse_entry(std::istream& in, state * ledger)
// transactions and create new virtual transactions for all that
// apply.
- for (state::virtual_map_iterator m = ledger->virtual_mapping.begin();
+ for (book::virtual_map_iterator m = ledger->virtual_mapping.begin();
m != ledger->virtual_mapping.end();
m++) {
std::list<transaction *> xacts;
@@ -301,7 +330,7 @@ entry * parse_entry(std::istream& in, state * ledger)
i++) {
transaction * t;
- if ((*i)->cost->comm()) {
+ if ((*i)->cost->commdty()) {
t = new transaction((*i)->acct, (*i)->cost);
} else {
amount * temp = (*x)->cost->value();
@@ -359,7 +388,7 @@ entry * parse_entry(std::istream& in, state * ledger)
x++) {
curr->xacts.push_back(*x);
- if (ledger->compute_balances)
+ if (do_compute)
(*x)->acct->balance.credit((*x)->cost);
}
}
@@ -379,7 +408,7 @@ entry * parse_entry(std::istream& in, state * ledger)
return curr;
}
-void parse_automated_transactions(std::istream& in, state * ledger)
+void parse_automated_transactions(std::istream& in, book * ledger)
{
static char line[MAX_LINE + 1];
@@ -415,7 +444,7 @@ void parse_automated_transactions(std::istream& in, state * ledger)
}
if (masks && xacts)
- ledger->virtual_mapping.insert(state::virtual_map_pair(masks, xacts));
+ ledger->virtual_mapping.insert(book::virtual_map_pair(masks, xacts));
else if (masks)
delete masks;
else if (xacts)
@@ -427,18 +456,18 @@ void parse_automated_transactions(std::istream& in, state * ledger)
// Ledger parser
//
-state * parse_ledger(std::istream& in, regexps_map& regexps,
+book * parse_ledger(std::istream& in, regexps_map& regexps,
bool compute_balances)
{
static char line[MAX_LINE + 1];
char c;
- state * ledger = new state;
- main_ledger = ledger;
+ book * ledger = new book;
- ledger->compute_balances = compute_balances;
+ main_ledger = ledger;
+ do_compute = compute_balances;
+ linenum = 0;
- linenum = 0;
while (! in.eof()) {
switch (in.peek()) {
case -1: // end of file
diff --git a/register.cc b/register.cc
index 38579ce0..db9b4849 100644
--- a/register.cc
+++ b/register.cc
@@ -4,12 +4,13 @@
namespace ledger {
-extern bool show_cleared;
+extern bool show_cleared;
+extern bool get_quotes;
extern std::time_t begin_date;
-extern bool have_beginning;
+extern bool have_beginning;
extern std::time_t end_date;
-extern bool have_ending;
+extern bool have_ending;
static std::string truncated(const std::string& str, int width)
{
@@ -83,7 +84,7 @@ void print_register(const std::string& acct_name, std::ostream& out,
// Always display the street value, if prices have been
// specified
- amount * street = (*x)->cost->street();
+ amount * street = (*x)->cost->street(get_quotes);
balance.credit(street);
// If there are two transactions, use the one which does not
@@ -126,7 +127,7 @@ void print_register(const std::string& acct_name, std::ostream& out,
out << std::left << truncated((*y)->acct_as_str(), 22) << " ";
out.width(12);
- street = (*y)->cost->street();
+ street = (*y)->cost->street(get_quotes);
out << std::right << street->as_str(true) << std::endl;
delete street;
}