*** empty log message ***
This commit is contained in:
parent
68e6b8538e
commit
a40813d896
8 changed files with 137 additions and 119 deletions
33
Makefile
33
Makefile
|
|
@ -1,22 +1,27 @@
|
||||||
define GNUCASH
|
CODE = amount.cc \
|
||||||
true
|
ledger.cc \
|
||||||
endef
|
parse.cc \
|
||||||
|
balance.cc \
|
||||||
CODE = amount.cc ledger.cc parse.cc \
|
register.cc \
|
||||||
balance.cc register.cc equity.cc main.cc
|
equity.cc \
|
||||||
ifdef GNUCASH
|
main.cc
|
||||||
CODE := $(CODE) gnucash.cc
|
|
||||||
endif
|
|
||||||
|
|
||||||
OBJS = $(patsubst %.cc,%.o,$(CODE))
|
OBJS = $(patsubst %.cc,%.o,$(CODE))
|
||||||
|
|
||||||
CFLAGS = -Wall -ansi -pedantic -DDEFAULT_COMMODITY="\"\$$\"" -DHUQUQULLAH=1
|
CFLAGS = -Wall -ansi -pedantic -DDEFAULT_COMMODITY="\"\$$\""
|
||||||
#DFLAGS = -O3 -fomit-frame-pointer
|
CFLAGS := $(CFLAGS) -DHUQUQULLAH=1
|
||||||
DFLAGS = -g # -pg
|
|
||||||
|
DFLAGS = -O3 -fomit-frame-pointer
|
||||||
|
#DFLAGS = -g -O2 # -pg
|
||||||
|
|
||||||
INCS = -I/usr/include/xmltok
|
INCS = -I/usr/include/xmltok
|
||||||
|
|
||||||
LIBS = -lgmpxx -lgmp -lpcre
|
LIBS = -lgmpxx -lgmp -lpcre
|
||||||
|
|
||||||
ifdef GNUCASH
|
ifdef GNUCASH
|
||||||
LIBS := $(LIBS) -lxmlparse
|
CODE := $(CODE) gnucash.cc
|
||||||
|
CFLAGS := $(CFLAGS) -DREAD_GNUCASH=1
|
||||||
|
LIBS := $(LIBS) -lxmlparse
|
||||||
endif
|
endif
|
||||||
|
|
||||||
all: make.deps ledger
|
all: make.deps ledger
|
||||||
|
|
@ -28,7 +33,7 @@ ledger: $(OBJS)
|
||||||
g++ $(CFLAGS) $(INCS) $(DFLAGS) -c -o $@ $<
|
g++ $(CFLAGS) $(INCS) $(DFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f libledger.so ledger *.o
|
rm -f ledger *.o
|
||||||
|
|
||||||
rebuild: clean deps all
|
rebuild: clean deps all
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -474,9 +474,12 @@ static commodity * parse_amount(mpz_t out, const char * num,
|
||||||
static char buf[256];
|
static char buf[256];
|
||||||
|
|
||||||
bool saw_commodity = false;
|
bool saw_commodity = false;
|
||||||
|
bool prefix = false;
|
||||||
|
bool separate = true;
|
||||||
|
bool thousands = true;
|
||||||
|
bool european = false;
|
||||||
|
|
||||||
std::string symbol;
|
std::string symbol;
|
||||||
bool prefix, separate, thousands, european;
|
|
||||||
int precision, result;
|
int precision, result;
|
||||||
|
|
||||||
if (ovector[base * 2] >= 0) {
|
if (ovector[base * 2] >= 0) {
|
||||||
|
|
|
||||||
90
balance.cc
90
balance.cc
|
|
@ -4,17 +4,17 @@
|
||||||
|
|
||||||
namespace ledger {
|
namespace ledger {
|
||||||
|
|
||||||
extern bool show_cleared;
|
extern bool show_cleared;
|
||||||
|
|
||||||
extern std::time_t begin_date;
|
extern std::time_t begin_date;
|
||||||
extern bool have_beginning;
|
extern bool have_beginning;
|
||||||
extern std::time_t end_date;
|
extern std::time_t end_date;
|
||||||
extern bool have_ending;
|
extern bool have_ending;
|
||||||
|
|
||||||
static bool show_children;
|
static bool show_children;
|
||||||
static bool show_empty;
|
static bool show_empty;
|
||||||
static bool no_subtotals;
|
static bool no_subtotals;
|
||||||
static bool full_names;
|
static bool full_names;
|
||||||
|
|
||||||
static bool account_matches(const account * acct,
|
static bool account_matches(const account * acct,
|
||||||
const std::list<mask>& regexps,
|
const std::list<mask>& regexps,
|
||||||
|
|
@ -41,31 +41,25 @@ static bool account_matches(const account * acct,
|
||||||
return match;
|
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 account * acct, bool top_level,
|
||||||
const std::map<account *, totals *>& balances,
|
|
||||||
const std::list<mask>& regexps)
|
const std::list<mask>& regexps)
|
||||||
{
|
{
|
||||||
bool displayed = false;
|
bool displayed = false;
|
||||||
|
|
||||||
std::map<account *, totals *>::const_iterator b =
|
if (acct->display && (show_empty || acct->balance)) {
|
||||||
balances.find(const_cast<account *>(acct));
|
displayed = true;
|
||||||
if (b != balances.end()) {
|
|
||||||
totals * balance = (*b).second;
|
|
||||||
if (balance && (show_empty || *balance)) {
|
|
||||||
displayed = true;
|
|
||||||
|
|
||||||
out << *balance;
|
out << acct->balance;
|
||||||
if (top_level)
|
if (top_level)
|
||||||
total_balance.credit(*balance);
|
balance.credit(acct->balance);
|
||||||
|
|
||||||
if (acct->parent && ! no_subtotals && ! full_names) {
|
if (acct->parent && ! no_subtotals && ! full_names) {
|
||||||
for (const account * a = acct; a; a = a->parent)
|
for (const account * a = acct; a; a = a->parent)
|
||||||
out << " ";
|
out << " ";
|
||||||
out << acct->name << std::endl;
|
out << acct->name << std::endl;
|
||||||
} else {
|
} else {
|
||||||
out << " " << *acct << std::endl;
|
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();
|
for (account::const_iterator i = acct->children.begin();
|
||||||
i != acct->children.end();
|
i != acct->children.end();
|
||||||
i++)
|
i++)
|
||||||
display_total(out, total_balance, (*i).second, ! displayed,
|
display_total(out, balance, (*i).second, ! displayed, regexps);
|
||||||
balances, 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
|
// Walk through all of the ledger entries, computing the account
|
||||||
// totals
|
// totals
|
||||||
|
|
||||||
std::map<account *, totals *> balances;
|
|
||||||
|
|
||||||
for (entries_iterator i = main_ledger.entries.begin();
|
for (entries_iterator i = main_ledger.entries.begin();
|
||||||
i != main_ledger.entries.end();
|
i != main_ledger.entries.end();
|
||||||
i++) {
|
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();
|
for (std::list<transaction *>::iterator x = (*i)->xacts.begin();
|
||||||
x != (*i)->xacts.end();
|
x != (*i)->xacts.end();
|
||||||
x++) {
|
x++) {
|
||||||
|
|
@ -140,27 +136,8 @@ void report_balances(int argc, char **argv, std::ostream& out)
|
||||||
else if (! (true_match || show_children || ! acct->parent))
|
else if (! (true_match || show_children || ! acct->parent))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
totals * balance = NULL;
|
acct->display = true;
|
||||||
|
acct->balance.credit((*x)->cost->street());
|
||||||
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());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -168,25 +145,18 @@ void report_balances(int argc, char **argv, std::ostream& out)
|
||||||
// Walk through all the top-level accounts, giving the balance
|
// Walk through all the top-level accounts, giving the balance
|
||||||
// report for each, and then for each of their children.
|
// report for each, and then for each of their children.
|
||||||
|
|
||||||
totals total_balance;
|
totals balance;
|
||||||
|
|
||||||
for (accounts_iterator i = main_ledger.accounts.begin();
|
for (accounts_iterator i = main_ledger.accounts.begin();
|
||||||
i != main_ledger.accounts.end();
|
i != main_ledger.accounts.end();
|
||||||
i++)
|
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
|
// Print the total of all the balances shown
|
||||||
|
|
||||||
if (! no_subtotals)
|
if (! no_subtotals)
|
||||||
out << "--------------------" << std::endl
|
out << "--------------------" << std::endl
|
||||||
<< total_balance << std::endl;
|
<< 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace ledger
|
} // namespace ledger
|
||||||
|
|
|
||||||
11
gnucash.cc
11
gnucash.cc
|
|
@ -17,8 +17,8 @@ static commodity * curr_comm;
|
||||||
static amount * curr_value;
|
static amount * curr_value;
|
||||||
static std::string curr_quant;
|
static std::string curr_quant;
|
||||||
static XML_Parser current_parser;
|
static XML_Parser current_parser;
|
||||||
|
static bool do_compute;
|
||||||
static accounts_t accounts_by_id;
|
static accounts_t accounts_by_id;
|
||||||
|
|
||||||
static enum {
|
static enum {
|
||||||
NO_ACTION,
|
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;
|
std::string value = curr_quant + " " + (*i).second->comm->symbol;
|
||||||
xact->cost = create_amount(value.c_str(), curr_value);
|
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;
|
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];
|
char buf[BUFSIZ];
|
||||||
|
|
||||||
curr_account = NULL;
|
curr_account = NULL;
|
||||||
curr_entry = NULL;
|
curr_entry = NULL;
|
||||||
curr_comm = NULL;
|
curr_comm = NULL;
|
||||||
|
do_compute = compute_balances;
|
||||||
|
|
||||||
action = NO_ACTION;
|
action = NO_ACTION;
|
||||||
|
|
||||||
|
|
|
||||||
17
ledger.cc
17
ledger.cc
|
|
@ -96,12 +96,16 @@ bool entry::matches(const std::list<mask>& regexps) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef DO_CLEANUP
|
||||||
|
|
||||||
totals::~totals()
|
totals::~totals()
|
||||||
{
|
{
|
||||||
for (iterator i = amounts.begin(); i != amounts.end(); i++)
|
for (iterator i = amounts.begin(); i != amounts.end(); i++)
|
||||||
delete (*i).second;
|
delete (*i).second;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif // DO_CLEANUP
|
||||||
|
|
||||||
void totals::credit(const totals& other)
|
void totals::credit(const totals& other)
|
||||||
{
|
{
|
||||||
for (const_iterator i = other.amounts.begin();
|
for (const_iterator i = other.amounts.begin();
|
||||||
|
|
@ -236,9 +240,10 @@ bool matches(const std::list<mask>& regexps, const std::string& str,
|
||||||
return match;
|
return match;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef DO_CLEANUP
|
||||||
|
|
||||||
state::~state()
|
state::~state()
|
||||||
{
|
{
|
||||||
#if 0
|
|
||||||
for (commodities_iterator i = commodities.begin();
|
for (commodities_iterator i = commodities.begin();
|
||||||
i != commodities.end();
|
i != commodities.end();
|
||||||
i++)
|
i++)
|
||||||
|
|
@ -253,9 +258,10 @@ state::~state()
|
||||||
i != entries.end();
|
i != entries.end();
|
||||||
i++)
|
i++)
|
||||||
delete *i;
|
delete *i;
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif // DO_CLEANUP
|
||||||
|
|
||||||
void state::record_price(const char * setting)
|
void state::record_price(const char * setting)
|
||||||
{
|
{
|
||||||
char buf[128];
|
char buf[128];
|
||||||
|
|
@ -275,6 +281,10 @@ void state::record_price(const char * setting)
|
||||||
|
|
||||||
account * state::find_account(const char * name, bool create)
|
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];
|
char * buf = new char[std::strlen(name) + 1];
|
||||||
std::strcpy(buf, name);
|
std::strcpy(buf, name);
|
||||||
|
|
||||||
|
|
@ -307,6 +317,9 @@ account * state::find_account(const char * name, bool create)
|
||||||
|
|
||||||
delete[] buf;
|
delete[] buf;
|
||||||
|
|
||||||
|
if (current)
|
||||||
|
accounts_cache.insert(accounts_entry(name, current));
|
||||||
|
|
||||||
return current;
|
return current;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
19
ledger.h
19
ledger.h
|
|
@ -1,5 +1,5 @@
|
||||||
#ifndef _LEDGER_H
|
#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) {}
|
transaction() : acct(NULL), cost(NULL) {}
|
||||||
|
|
||||||
|
#ifdef DO_CLEANUP
|
||||||
~transaction() {
|
~transaction() {
|
||||||
if (cost)
|
if (cost)
|
||||||
delete cost;
|
delete cost;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
struct entry
|
struct entry
|
||||||
|
|
@ -189,6 +191,12 @@ struct entry
|
||||||
std::list<transaction *> xacts;
|
std::list<transaction *> xacts;
|
||||||
|
|
||||||
entry() : cleared(false) {}
|
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() {
|
~entry() {
|
||||||
for (std::list<transaction *>::iterator i = xacts.begin();
|
for (std::list<transaction *>::iterator i = xacts.begin();
|
||||||
i != xacts.end();
|
i != xacts.end();
|
||||||
|
|
@ -196,6 +204,7 @@ struct entry
|
||||||
delete *i;
|
delete *i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
bool matches(const std::list<mask>& regexps) const;
|
bool matches(const std::list<mask>& regexps) const;
|
||||||
void print(std::ostream& out) const;
|
void print(std::ostream& out) const;
|
||||||
|
|
@ -221,7 +230,9 @@ struct totals
|
||||||
|
|
||||||
map amounts;
|
map amounts;
|
||||||
|
|
||||||
|
#ifdef DO_CLEANUP
|
||||||
~totals();
|
~totals();
|
||||||
|
#endif
|
||||||
|
|
||||||
void credit(const amount * val) {
|
void credit(const amount * val) {
|
||||||
std::pair<iterator, bool> result =
|
std::pair<iterator, bool> result =
|
||||||
|
|
@ -257,6 +268,7 @@ struct account
|
||||||
std::string name;
|
std::string name;
|
||||||
commodity * comm; // default commodity for this account
|
commodity * comm; // default commodity for this account
|
||||||
totals balance;
|
totals balance;
|
||||||
|
bool display;
|
||||||
|
|
||||||
typedef std::map<const std::string, struct account *> map;
|
typedef std::map<const std::string, struct account *> map;
|
||||||
typedef map::iterator iterator;
|
typedef map::iterator iterator;
|
||||||
|
|
@ -266,7 +278,7 @@ struct account
|
||||||
map children;
|
map children;
|
||||||
|
|
||||||
account(const std::string& _name, struct account * _parent = NULL)
|
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 {
|
const std::string as_str() const {
|
||||||
if (! parent)
|
if (! parent)
|
||||||
|
|
@ -297,10 +309,13 @@ struct state
|
||||||
{
|
{
|
||||||
commodities_t commodities;
|
commodities_t commodities;
|
||||||
accounts_t accounts;
|
accounts_t accounts;
|
||||||
|
accounts_t accounts_cache; // maps full names to accounts
|
||||||
entries_t entries;
|
entries_t entries;
|
||||||
totals prices;
|
totals prices;
|
||||||
|
|
||||||
|
#ifdef DO_CLEANUP
|
||||||
~state();
|
~state();
|
||||||
|
#endif
|
||||||
|
|
||||||
void record_price(const char * setting);
|
void record_price(const char * setting);
|
||||||
account * find_account(const char * name, bool create = true);
|
account * find_account(const char * name, bool create = true);
|
||||||
|
|
|
||||||
14
main.cc
14
main.cc
|
|
@ -3,8 +3,10 @@
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
namespace ledger {
|
namespace ledger {
|
||||||
extern bool parse_ledger(std::istream& in);
|
extern bool parse_ledger(std::istream& in, bool compute_balances);
|
||||||
extern bool parse_gnucash(std::istream& in);
|
#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 report_balances(int argc, char **argv, std::ostream& out);
|
||||||
extern void print_register(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
|
// Parse the ledger
|
||||||
|
|
||||||
|
#ifdef READ_GNUCASH
|
||||||
char buf[32];
|
char buf[32];
|
||||||
file->get(buf, 31);
|
file->get(buf, 31);
|
||||||
file->seekg(0);
|
file->seekg(0);
|
||||||
|
|
||||||
if (std::strncmp(buf, "<?xml version=\"1.0\"?>", 21) == 0)
|
if (std::strncmp(buf, "<?xml version=\"1.0\"?>", 21) == 0)
|
||||||
parse_gnucash(*file);
|
parse_gnucash(*file, command == "equity");
|
||||||
else
|
else
|
||||||
parse_ledger(*file);
|
#endif
|
||||||
|
parse_ledger(*file, command == "equity");
|
||||||
|
|
||||||
|
#ifdef DO_CLEANUP
|
||||||
delete file;
|
delete file;
|
||||||
|
#endif
|
||||||
|
|
||||||
// Process the command
|
// Process the command
|
||||||
|
|
||||||
|
|
|
||||||
67
parse.cc
67
parse.cc
|
|
@ -50,38 +50,33 @@ static inline void finalize_entry(entry * curr)
|
||||||
// Ledger parser
|
// 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);
|
std::time_t now = std::time(NULL);
|
||||||
static struct std::tm * now_tm = std::localtime(&now);
|
struct std::tm * now_tm = std::localtime(&now);
|
||||||
static int current_year = now_tm->tm_year + 1900;
|
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));
|
memset(&moment, 0, sizeof(struct std::tm));
|
||||||
|
|
||||||
entry * curr = NULL;
|
entry * curr = NULL;
|
||||||
|
|
||||||
// Compile the regular expression used for parsing amounts
|
// Compile the regular expression used for parsing amounts
|
||||||
static pcre * entry_re = NULL;
|
const char *error;
|
||||||
if (! entry_re) {
|
int erroffset;
|
||||||
const char *error;
|
static const std::string regexp =
|
||||||
int erroffset;
|
"^(([0-9]{4})[./])?([0-9]+)[./]([0-9]+)\\s+(\\*\\s+)?"
|
||||||
static const std::string regexp =
|
"(\\(([^)]+)\\)\\s+)?(.+)";
|
||||||
"^(([0-9]{4})[./])?([0-9]+)[./]([0-9]+)\\s+(\\*\\s+)?"
|
pcre * entry_re = pcre_compile(regexp.c_str(), 0,
|
||||||
"(\\(([^)]+)\\)\\s+)?(.+)";
|
&error, &erroffset, NULL);
|
||||||
entry_re = pcre_compile(regexp.c_str(), 0, &error, &erroffset, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
while (! in.eof()) {
|
while (! in.eof()) {
|
||||||
in.getline(line, 1023);
|
in.getline(line, 1023);
|
||||||
linenum++;
|
linenum++;
|
||||||
|
|
||||||
if (in.eof()) {
|
if (line[0] == '\n') {
|
||||||
break;
|
|
||||||
}
|
|
||||||
else if (line[0] == '\n') {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else if (std::isdigit(line[0])) {
|
else if (std::isdigit(line[0])) {
|
||||||
|
|
@ -96,28 +91,28 @@ bool parse_ledger(std::istream& in)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we haven't finished with the last entry yet, do so now
|
||||||
|
|
||||||
if (curr)
|
if (curr)
|
||||||
finalize_entry(curr);
|
finalize_entry(curr);
|
||||||
|
|
||||||
curr = new entry;
|
curr = new entry;
|
||||||
|
|
||||||
// Parse the date
|
// Parse the date
|
||||||
|
|
||||||
int mday, mon, year = current_year;
|
int year = current_year;
|
||||||
|
|
||||||
if (ovector[1 * 2] >= 0) {
|
if (ovector[1 * 2] >= 0) {
|
||||||
pcre_copy_substring(line, ovector, matched, 2, buf, 255);
|
pcre_copy_substring(line, ovector, matched, 2, buf, 255);
|
||||||
year = std::atoi(buf);
|
year = std::atoi(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ovector[3 * 2] >= 0) {
|
assert(ovector[3 * 2] >= 0);
|
||||||
pcre_copy_substring(line, ovector, matched, 3, buf, 255);
|
pcre_copy_substring(line, ovector, matched, 3, buf, 255);
|
||||||
mon = std::atoi(buf);
|
int mon = std::atoi(buf);
|
||||||
}
|
|
||||||
|
|
||||||
if (ovector[4 * 2] >= 0) {
|
assert(ovector[4 * 2] >= 0);
|
||||||
pcre_copy_substring(line, ovector, matched, 4, buf, 255);
|
pcre_copy_substring(line, ovector, matched, 4, buf, 255);
|
||||||
mday = std::atoi(buf);
|
int mday = std::atoi(buf);
|
||||||
}
|
|
||||||
|
|
||||||
moment.tm_mday = mday;
|
moment.tm_mday = mday;
|
||||||
moment.tm_mon = mon - 1;
|
moment.tm_mon = mon - 1;
|
||||||
|
|
@ -125,6 +120,8 @@ bool parse_ledger(std::istream& in)
|
||||||
|
|
||||||
curr->date = std::mktime(&moment);
|
curr->date = std::mktime(&moment);
|
||||||
|
|
||||||
|
// Parse the remaining entry details
|
||||||
|
|
||||||
if (ovector[5 * 2] >= 0)
|
if (ovector[5 * 2] >= 0)
|
||||||
curr->cleared = true;
|
curr->cleared = true;
|
||||||
|
|
||||||
|
|
@ -164,6 +161,7 @@ bool parse_ledger(std::istream& in)
|
||||||
cost_str++;
|
cost_str++;
|
||||||
xact->note = cost_str;
|
xact->note = cost_str;
|
||||||
}
|
}
|
||||||
|
|
||||||
xact->cost = curr->xacts.front()->cost->copy();
|
xact->cost = curr->xacts.front()->cost->copy();
|
||||||
xact->cost->negate();
|
xact->cost->negate();
|
||||||
}
|
}
|
||||||
|
|
@ -198,7 +196,8 @@ bool parse_ledger(std::istream& in)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
xact->acct = main_ledger.find_account(p);
|
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);
|
curr->xacts.push_back(xact);
|
||||||
|
|
||||||
|
|
@ -215,9 +214,11 @@ bool parse_ledger(std::istream& in)
|
||||||
temp = xact->cost->value();
|
temp = xact->cost->value();
|
||||||
t->cost = temp->value(huquq);
|
t->cost = temp->value(huquq);
|
||||||
delete temp;
|
delete temp;
|
||||||
t->acct->balance.credit(t->cost);
|
|
||||||
curr->xacts.push_back(t);
|
curr->xacts.push_back(t);
|
||||||
|
|
||||||
|
if (compute_balances)
|
||||||
|
t->acct->balance.credit(t->cost);
|
||||||
|
|
||||||
// Balance the above transaction by recording the inverse in
|
// Balance the above transaction by recording the inverse in
|
||||||
// Expenses:Huququ'llah.
|
// Expenses:Huququ'llah.
|
||||||
t = new transaction();
|
t = new transaction();
|
||||||
|
|
@ -226,8 +227,10 @@ bool parse_ledger(std::istream& in)
|
||||||
t->cost = temp->value(huquq);
|
t->cost = temp->value(huquq);
|
||||||
delete temp;
|
delete temp;
|
||||||
t->cost->negate();
|
t->cost->negate();
|
||||||
t->acct->balance.credit(t->cost);
|
|
||||||
curr->xacts.push_back(t);
|
curr->xacts.push_back(t);
|
||||||
|
|
||||||
|
if (compute_balances)
|
||||||
|
t->acct->balance.credit(t->cost);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue