*** empty log message ***

This commit is contained in:
John Wiegley 2003-10-01 07:11:57 +00:00
parent 68e6b8538e
commit a40813d896
8 changed files with 137 additions and 119 deletions

View file

@ -1,22 +1,27 @@
define GNUCASH
true
endef
CODE = amount.cc ledger.cc parse.cc \
balance.cc register.cc equity.cc main.cc
ifdef GNUCASH
CODE := $(CODE) gnucash.cc
endif
CODE = amount.cc \
ledger.cc \
parse.cc \
balance.cc \
register.cc \
equity.cc \
main.cc
OBJS = $(patsubst %.cc,%.o,$(CODE))
CFLAGS = -Wall -ansi -pedantic -DDEFAULT_COMMODITY="\"\$$\"" -DHUQUQULLAH=1
#DFLAGS = -O3 -fomit-frame-pointer
DFLAGS = -g # -pg
CFLAGS = -Wall -ansi -pedantic -DDEFAULT_COMMODITY="\"\$$\""
CFLAGS := $(CFLAGS) -DHUQUQULLAH=1
DFLAGS = -O3 -fomit-frame-pointer
#DFLAGS = -g -O2 # -pg
INCS = -I/usr/include/xmltok
LIBS = -lgmpxx -lgmp -lpcre
ifdef GNUCASH
LIBS := $(LIBS) -lxmlparse
CODE := $(CODE) gnucash.cc
CFLAGS := $(CFLAGS) -DREAD_GNUCASH=1
LIBS := $(LIBS) -lxmlparse
endif
all: make.deps ledger
@ -28,7 +33,7 @@ ledger: $(OBJS)
g++ $(CFLAGS) $(INCS) $(DFLAGS) -c -o $@ $<
clean:
rm -f libledger.so ledger *.o
rm -f ledger *.o
rebuild: clean deps all

View file

@ -474,9 +474,12 @@ static commodity * parse_amount(mpz_t out, const char * num,
static char buf[256];
bool saw_commodity = false;
bool prefix = false;
bool separate = true;
bool thousands = true;
bool european = false;
std::string symbol;
bool prefix, separate, thousands, european;
int precision, result;
if (ovector[base * 2] >= 0) {

View file

@ -4,17 +4,17 @@
namespace ledger {
extern bool show_cleared;
extern bool show_cleared;
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 bool show_children;
static bool show_empty;
static bool no_subtotals;
static bool full_names;
static bool show_children;
static bool show_empty;
static bool no_subtotals;
static bool full_names;
static bool account_matches(const account * acct,
const std::list<mask>& regexps,
@ -41,31 +41,25 @@ static bool account_matches(const account * acct,
return match;
}
static void display_total(std::ostream& out, totals& total_balance,
static void display_total(std::ostream& out, totals& balance,
const account * acct, bool top_level,
const std::map<account *, totals *>& balances,
const std::list<mask>& regexps)
{
bool displayed = false;
std::map<account *, totals *>::const_iterator b =
balances.find(const_cast<account *>(acct));
if (b != balances.end()) {
totals * balance = (*b).second;
if (balance && (show_empty || *balance)) {
displayed = true;
if (acct->display && (show_empty || acct->balance)) {
displayed = true;
out << *balance;
if (top_level)
total_balance.credit(*balance);
out << acct->balance;
if (top_level)
balance.credit(acct->balance);
if (acct->parent && ! no_subtotals && ! full_names) {
for (const account * a = acct; a; a = a->parent)
out << " ";
out << acct->name << std::endl;
} else {
out << " " << *acct << std::endl;
}
if (acct->parent && ! no_subtotals && ! full_names) {
for (const account * a = acct; a; a = a->parent)
out << " ";
out << acct->name << std::endl;
} else {
out << " " << *acct << std::endl;
}
}
@ -74,8 +68,7 @@ static void display_total(std::ostream& out, totals& total_balance,
for (account::const_iterator i = acct->children.begin();
i != acct->children.end();
i++)
display_total(out, total_balance, (*i).second, ! displayed,
balances, regexps);
display_total(out, balance, (*i).second, ! displayed, regexps);
}
//////////////////////////////////////////////////////////////////////
@ -122,11 +115,14 @@ void report_balances(int argc, char **argv, std::ostream& out)
// Walk through all of the ledger entries, computing the account
// totals
std::map<account *, totals *> balances;
for (entries_iterator i = main_ledger.entries.begin();
i != main_ledger.entries.end();
i++) {
if ((have_beginning && difftime((*i)->date, begin_date) < 0) ||
(have_ending && difftime((*i)->date, end_date) >= 0) ||
(show_cleared && ! (*i)->cleared))
continue;
for (std::list<transaction *>::iterator x = (*i)->xacts.begin();
x != (*i)->xacts.end();
x++) {
@ -140,27 +136,8 @@ void report_balances(int argc, char **argv, std::ostream& out)
else if (! (true_match || show_children || ! acct->parent))
continue;
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;
}
bool do_credit = true;
if (have_beginning && difftime((*i)->date, begin_date) < 0)
do_credit = false;
else if (have_ending && difftime((*i)->date, end_date) > 0)
do_credit = false;
else if (show_cleared && ! (*i)->cleared)
do_credit = false;
if (! do_credit)
continue;
balance->credit((*x)->cost->street());
acct->display = true;
acct->balance.credit((*x)->cost->street());
}
}
}
@ -168,25 +145,18 @@ void report_balances(int argc, char **argv, std::ostream& out)
// Walk through all the top-level accounts, giving the balance
// report for each, and then for each of their children.
totals total_balance;
totals balance;
for (accounts_iterator i = main_ledger.accounts.begin();
i != main_ledger.accounts.end();
i++)
display_total(out, total_balance, (*i).second, true, balances, regexps);
display_total(out, balance, (*i).second, true, regexps);
// Print the total of all the balances shown
if (! no_subtotals)
out << "--------------------" << std::endl
<< 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;
<< balance << std::endl;
}
} // namespace ledger

View file

@ -17,8 +17,8 @@ static commodity * curr_comm;
static amount * curr_value;
static std::string curr_quant;
static XML_Parser current_parser;
static accounts_t accounts_by_id;
static bool do_compute;
static accounts_t accounts_by_id;
static enum {
NO_ACTION,
@ -205,7 +205,9 @@ static void dataHandler(void *userData, const char *s, int len)
std::string value = curr_quant + " " + (*i).second->comm->symbol;
xact->cost = create_amount(value.c_str(), curr_value);
xact->acct->balance.credit(xact->cost);
if (do_compute)
xact->acct->balance.credit(xact->cost);
break;
}
@ -224,13 +226,14 @@ static void dataHandler(void *userData, const char *s, int len)
}
}
bool parse_gnucash(std::istream& in)
bool parse_gnucash(std::istream& in, bool compute_balances)
{
char buf[BUFSIZ];
curr_account = NULL;
curr_entry = NULL;
curr_comm = NULL;
do_compute = compute_balances;
action = NO_ACTION;

View file

@ -96,12 +96,16 @@ bool entry::matches(const std::list<mask>& regexps) const
}
}
#ifdef DO_CLEANUP
totals::~totals()
{
for (iterator i = amounts.begin(); i != amounts.end(); i++)
delete (*i).second;
}
#endif // DO_CLEANUP
void totals::credit(const totals& other)
{
for (const_iterator i = other.amounts.begin();
@ -236,9 +240,10 @@ bool matches(const std::list<mask>& regexps, const std::string& str,
return match;
}
#ifdef DO_CLEANUP
state::~state()
{
#if 0
for (commodities_iterator i = commodities.begin();
i != commodities.end();
i++)
@ -253,9 +258,10 @@ state::~state()
i != entries.end();
i++)
delete *i;
#endif
}
#endif // DO_CLEANUP
void state::record_price(const char * setting)
{
char buf[128];
@ -275,6 +281,10 @@ void state::record_price(const char * setting)
account * state::find_account(const char * name, bool create)
{
accounts_iterator i = accounts_cache.find(name);
if (i != accounts_cache.end())
return (*i).second;
char * buf = new char[std::strlen(name) + 1];
std::strcpy(buf, name);
@ -307,6 +317,9 @@ account * state::find_account(const char * name, bool create)
delete[] buf;
if (current)
accounts_cache.insert(accounts_entry(name, current));
return current;
}

View file

@ -1,5 +1,5 @@
#ifndef _LEDGER_H
#define _LEDGER_H "$Revision: 1.11 $"
#define _LEDGER_H "$Revision: 1.12 $"
//////////////////////////////////////////////////////////////////////
//
@ -172,10 +172,12 @@ struct transaction
transaction() : acct(NULL), cost(NULL) {}
#ifdef DO_CLEANUP
~transaction() {
if (cost)
delete cost;
}
#endif
};
struct entry
@ -189,6 +191,12 @@ struct entry
std::list<transaction *> xacts;
entry() : cleared(false) {}
#ifdef DO_CLEANUP
// If we're running as a command-line tool, it's cheaper to just
// throw away the heap on exit, than spend time freeing things up
// like a good citizen.
~entry() {
for (std::list<transaction *>::iterator i = xacts.begin();
i != xacts.end();
@ -196,6 +204,7 @@ struct entry
delete *i;
}
}
#endif
bool matches(const std::list<mask>& regexps) const;
void print(std::ostream& out) const;
@ -221,7 +230,9 @@ struct totals
map amounts;
#ifdef DO_CLEANUP
~totals();
#endif
void credit(const amount * val) {
std::pair<iterator, bool> result =
@ -257,6 +268,7 @@ struct account
std::string name;
commodity * comm; // default commodity for this account
totals balance;
bool display;
typedef std::map<const std::string, struct account *> map;
typedef map::iterator iterator;
@ -266,7 +278,7 @@ struct account
map children;
account(const std::string& _name, struct account * _parent = NULL)
: parent(_parent), name(_name) {}
: parent(_parent), name(_name), display(false) {}
const std::string as_str() const {
if (! parent)
@ -297,10 +309,13 @@ struct state
{
commodities_t commodities;
accounts_t accounts;
accounts_t accounts_cache; // maps full names to accounts
entries_t entries;
totals prices;
#ifdef DO_CLEANUP
~state();
#endif
void record_price(const char * setting);
account * find_account(const char * name, bool create = true);

14
main.cc
View file

@ -3,8 +3,10 @@
#include <fstream>
namespace ledger {
extern bool parse_ledger(std::istream& in);
extern bool parse_gnucash(std::istream& in);
extern bool parse_ledger(std::istream& in, bool compute_balances);
#ifdef READ_GNUCASH
extern bool parse_gnucash(std::istream& in, bool compute_balances);
#endif
extern void report_balances(int argc, char **argv, std::ostream& out);
extern void print_register(int argc, char **argv, std::ostream& out);
@ -188,16 +190,20 @@ int main(int argc, char *argv[])
// Parse the ledger
#ifdef READ_GNUCASH
char buf[32];
file->get(buf, 31);
file->seekg(0);
if (std::strncmp(buf, "<?xml version=\"1.0\"?>", 21) == 0)
parse_gnucash(*file);
parse_gnucash(*file, command == "equity");
else
parse_ledger(*file);
#endif
parse_ledger(*file, command == "equity");
#ifdef DO_CLEANUP
delete file;
#endif
// Process the command

View file

@ -50,38 +50,33 @@ static inline void finalize_entry(entry * curr)
// Ledger parser
//
bool parse_ledger(std::istream& in)
bool parse_ledger(std::istream& in, bool compute_balances)
{
static std::time_t now = std::time(NULL);
static struct std::tm * now_tm = std::localtime(&now);
static int current_year = now_tm->tm_year + 1900;
std::time_t now = std::time(NULL);
struct std::tm * now_tm = std::localtime(&now);
int current_year = now_tm->tm_year + 1900;
static char line[1024];
char line[1024];
static struct std::tm moment;
struct std::tm moment;
memset(&moment, 0, sizeof(struct std::tm));
entry * curr = NULL;
// Compile the regular expression used for parsing amounts
static pcre * entry_re = NULL;
if (! entry_re) {
const char *error;
int erroffset;
static const std::string regexp =
"^(([0-9]{4})[./])?([0-9]+)[./]([0-9]+)\\s+(\\*\\s+)?"
"(\\(([^)]+)\\)\\s+)?(.+)";
entry_re = pcre_compile(regexp.c_str(), 0, &error, &erroffset, NULL);
}
const char *error;
int erroffset;
static const std::string regexp =
"^(([0-9]{4})[./])?([0-9]+)[./]([0-9]+)\\s+(\\*\\s+)?"
"(\\(([^)]+)\\)\\s+)?(.+)";
pcre * entry_re = pcre_compile(regexp.c_str(), 0,
&error, &erroffset, NULL);
while (! in.eof()) {
in.getline(line, 1023);
linenum++;
if (in.eof()) {
break;
}
else if (line[0] == '\n') {
if (line[0] == '\n') {
continue;
}
else if (std::isdigit(line[0])) {
@ -96,28 +91,28 @@ bool parse_ledger(std::istream& in)
continue;
}
// If we haven't finished with the last entry yet, do so now
if (curr)
finalize_entry(curr);
curr = new entry;
// Parse the date
int mday, mon, year = current_year;
int year = current_year;
if (ovector[1 * 2] >= 0) {
pcre_copy_substring(line, ovector, matched, 2, buf, 255);
year = std::atoi(buf);
}
if (ovector[3 * 2] >= 0) {
pcre_copy_substring(line, ovector, matched, 3, buf, 255);
mon = std::atoi(buf);
}
assert(ovector[3 * 2] >= 0);
pcre_copy_substring(line, ovector, matched, 3, buf, 255);
int mon = std::atoi(buf);
if (ovector[4 * 2] >= 0) {
pcre_copy_substring(line, ovector, matched, 4, buf, 255);
mday = std::atoi(buf);
}
assert(ovector[4 * 2] >= 0);
pcre_copy_substring(line, ovector, matched, 4, buf, 255);
int mday = std::atoi(buf);
moment.tm_mday = mday;
moment.tm_mon = mon - 1;
@ -125,6 +120,8 @@ bool parse_ledger(std::istream& in)
curr->date = std::mktime(&moment);
// Parse the remaining entry details
if (ovector[5 * 2] >= 0)
curr->cleared = true;
@ -164,6 +161,7 @@ bool parse_ledger(std::istream& in)
cost_str++;
xact->note = cost_str;
}
xact->cost = curr->xacts.front()->cost->copy();
xact->cost->negate();
}
@ -198,7 +196,8 @@ bool parse_ledger(std::istream& in)
#endif
xact->acct = main_ledger.find_account(p);
xact->acct->balance.credit(xact->cost);
if (compute_balances)
xact->acct->balance.credit(xact->cost);
curr->xacts.push_back(xact);
@ -215,9 +214,11 @@ bool parse_ledger(std::istream& in)
temp = xact->cost->value();
t->cost = temp->value(huquq);
delete temp;
t->acct->balance.credit(t->cost);
curr->xacts.push_back(t);
if (compute_balances)
t->acct->balance.credit(t->cost);
// Balance the above transaction by recording the inverse in
// Expenses:Huququ'llah.
t = new transaction();
@ -226,8 +227,10 @@ bool parse_ledger(std::istream& in)
t->cost = temp->value(huquq);
delete temp;
t->cost->negate();
t->acct->balance.credit(t->cost);
curr->xacts.push_back(t);
if (compute_balances)
t->acct->balance.credit(t->cost);
}
#endif
}