two major changes

Complete changed the way format strings are handled.  They are now
compiled first, which is far more efficient than what was being done
before.

Also, there is now a global ledger::commodity_t::commodities map,
which saves me from having to pass the current journal around to a
zillion different functions, for the sole purpose of making sure that
all commodity symbols that are parsed refer to the same commodity
object.
This commit is contained in:
John Wiegley 2004-07-30 21:57:02 -04:00
parent 5087a60dee
commit 94e76ae87e
16 changed files with 651 additions and 575 deletions

View file

@ -10,8 +10,6 @@
namespace ledger { namespace ledger {
commodity_t * amount_t::null_commodity = NULL;
static void mpz_round(mpz_t value, int precision) static void mpz_round(mpz_t value, int precision)
{ {
mpz_t divisor; mpz_t divisor;
@ -544,7 +542,7 @@ void parse_commodity(std::istream& in, std::string& symbol)
} }
} }
void amount_t::parse(std::istream& in, ledger_t * ledger) void amount_t::parse(std::istream& in)
{ {
// The possible syntax for an amount is: // The possible syntax for an amount is:
// //
@ -607,25 +605,10 @@ void amount_t::parse(std::istream& in, ledger_t * ledger)
assert(precision <= MAX_PRECISION); assert(precision <= MAX_PRECISION);
// Create the commodity if has not already been seen. // Create the commodity if has not already been seen.
if (ledger) { commodity = commodity_t::find_commodity(symbol, true);
commodity = ledger->find_commodity(symbol, true);
commodity->flags |= flags; commodity->flags |= flags;
if (precision > commodity->precision) if (precision > commodity->precision)
commodity->precision = precision; commodity->precision = precision;
}
else if (symbol.empty()) {
if (! null_commodity) {
commodity = null_commodity = new commodity_t(symbol, precision, flags);
} else {
commodity = null_commodity;
commodity->flags |= flags;
if (precision > commodity->precision)
commodity->precision = precision;
}
}
else {
commodity = new commodity_t(symbol, precision, flags);
}
// The number is specified as the user desires, with the commodity // The number is specified as the user desires, with the commodity
// flags telling how to parse it. // flags telling how to parse it.
@ -696,6 +679,24 @@ void (*commodity_t::updater)(commodity_t * commodity,
const amount_t& price, const amount_t& price,
const std::time_t moment) = NULL; const std::time_t moment) = NULL;
commodities_map commodity_t::commodities;
commodity_t * commodity_t::find_commodity(const std::string& symbol,
bool auto_create)
{
commodities_map::const_iterator i = commodities.find(symbol);
if (i != commodities.end())
return (*i).second;
if (auto_create) {
commodity_t * commodity = new commodity_t(symbol);
add_commodity(commodity);
return commodity;
}
return NULL;
}
amount_t commodity_t::value(const std::time_t moment) amount_t commodity_t::value(const std::time_t moment)
{ {
std::time_t age = 0; std::time_t age = 0;

View file

@ -343,7 +343,7 @@ unsigned int read_binary_ledger(std::istream& in,
for (int i = count; --i >= 0; ) { for (int i = count; --i >= 0; ) {
commodity_t * commodity = read_binary_commodity(in); commodity_t * commodity = read_binary_commodity(in);
std::pair<commodities_map::iterator, bool> result std::pair<commodities_map::iterator, bool> result
= ledger->commodities.insert(commodities_pair(commodity->symbol, = commodity_t::commodities.insert(commodities_pair(commodity->symbol,
commodity)); commodity));
assert(result.second || master); assert(result.second || master);
} }
@ -593,11 +593,11 @@ void write_binary_ledger(std::ostream& out, ledger_t * ledger,
write_binary_account(out, ledger->master); write_binary_account(out, ledger->master);
unsigned long count = ledger->commodities.size(); unsigned long count = commodity_t::commodities.size();
out.write((char *)&count, sizeof(count)); out.write((char *)&count, sizeof(count));
for (commodities_map::const_iterator i = ledger->commodities.begin(); for (commodities_map::const_iterator i = commodity_t::commodities.begin();
i != ledger->commodities.end(); i != commodity_t::commodities.end();
i++) i++)
write_binary_commodity(out, (*i).second); write_binary_commodity(out, (*i).second);

View file

@ -9,7 +9,7 @@ extern unsigned long magic_number;
extern unsigned int read_binary_ledger(std::istream& in, extern unsigned int read_binary_ledger(std::istream& in,
const std::string& leader, const std::string& leader,
ledger_t * book, ledger_t * journal,
account_t * master = NULL); account_t * master = NULL);
extern void write_binary_ledger(std::ostream& out, extern void write_binary_ledger(std::ostream& out,

View file

@ -93,10 +93,10 @@ bool matches(const masks_list& regexps, const std::string& str,
bool constraints_t::matches_date_range(const std::time_t date) const bool constraints_t::matches_date_range(const std::time_t date) const
{ {
if (have_beginning && difftime(date, begin_date) < 0) if (begin_date != -1 && difftime(date, begin_date) < 0)
return false; return false;
if (have_ending && difftime(date, end_date) >= 0) if (end_date != -1 && difftime(date, end_date) >= 0)
return false; return false;
if (have_date_mask) { if (have_date_mask) {

View file

@ -104,9 +104,7 @@ class constraints_t
bool show_empty; bool show_empty;
std::time_t begin_date; std::time_t begin_date;
bool have_beginning;
std::time_t end_date; std::time_t end_date;
bool have_ending;
struct std::tm date_mask; struct std::tm date_mask;
bool have_date_mask; bool have_date_mask;
@ -128,8 +126,8 @@ class constraints_t
show_subtotals = true; show_subtotals = true;
show_empty = false; show_empty = false;
have_beginning = false; begin_date = -1;
have_ending = false; end_date = -1;
have_date_mask = false; have_date_mask = false;
period = PERIOD_NONE; period = PERIOD_NONE;
@ -140,11 +138,11 @@ class constraints_t
~constraints_t(); ~constraints_t();
std::time_t begin() const { std::time_t begin() const {
return have_beginning ? begin_date : 0; return begin_date == -1 ? 0 : begin_date;
} }
std::time_t end() const { std::time_t end() const {
return have_ending ? end_date : std::time(NULL); return end_date == -1 ? std::time(NULL) : end_date;
} }
bool matches_date_range(const std::time_t date) const; bool matches_date_range(const std::time_t date) const;

View file

@ -32,6 +32,13 @@ class expr_error : public error
virtual ~expr_error() throw() {} virtual ~expr_error() throw() {}
}; };
class format_error : public error
{
public:
format_error(const std::string& reason) throw() : error(reason) {}
virtual ~format_error() throw() {}
};
class parse_error : public error class parse_error : public error
{ {
unsigned int line; unsigned int line;

228
expr.cc
View file

@ -149,14 +149,14 @@ balance_t node_t::compute(const item_t * item,
return temp; return temp;
} }
node_t * parse_term(std::istream& in, ledger_t * ledger); node_t * parse_term(std::istream& in);
inline node_t * parse_term(const char * p, ledger_t * ledger) { inline node_t * parse_term(const char * p) {
std::istringstream stream(p); std::istringstream stream(p);
return parse_term(stream, ledger); return parse_term(stream);
} }
node_t * parse_term(std::istream& in, ledger_t * ledger) node_t * parse_term(std::istream& in)
{ {
node_t * node = NULL; node_t * node = NULL;
@ -185,8 +185,8 @@ node_t * parse_term(std::istream& in, ledger_t * ledger)
} }
if (! ident.empty()) { if (! ident.empty()) {
node = new node_t(CONSTANT_A); node = new node_t(node_t::CONSTANT_A);
node->constant_a.parse(ident, ledger); node->constant_a.parse(ident);
} }
return node; return node;
} }
@ -194,62 +194,62 @@ node_t * parse_term(std::istream& in, ledger_t * ledger)
in.get(c); in.get(c);
switch (c) { switch (c) {
// Basic terms // Basic terms
case 'a': node = new node_t(AMOUNT); break; case 'a': node = new node_t(node_t::AMOUNT); break;
case 'c': node = new node_t(COST); break; case 'c': node = new node_t(node_t::COST); break;
case 'd': node = new node_t(DATE); break; case 'd': node = new node_t(node_t::DATE); break;
case 'b': node = new node_t(BEGIN_DATE); break; case 'b': node = new node_t(node_t::BEGIN_DATE); break;
case 'e': node = new node_t(END_DATE); break; case 'e': node = new node_t(node_t::END_DATE); break;
case 'i': node = new node_t(INDEX); break; case 'i': node = new node_t(node_t::INDEX); break;
case 'B': node = new node_t(BALANCE); break; case 'B': node = new node_t(node_t::BALANCE); break;
case 'T': node = new node_t(TOTAL); break; case 'T': node = new node_t(node_t::TOTAL); break;
case 'C': node = new node_t(COST_TOTAL); break; case 'C': node = new node_t(node_t::COST_TOTAL); break;
// Compound terms // Compound terms
case 'v': node = parse_expr("P(a,d)", ledger); break; case 'v': node = parse_expr("P(a,d)"); break;
case 'V': node = parse_term("P(T,d)", ledger); break; case 'V': node = parse_term("P(T,d)"); break;
case 'g': node = parse_expr("v-c", ledger); break; case 'g': node = parse_expr("v-c"); break;
case 'G': node = parse_expr("V-C", ledger); break; case 'G': node = parse_expr("V-C"); break;
case 'o': node = parse_expr("d-b", ledger); break; case 'o': node = parse_expr("d-b"); break;
case 'w': node = parse_expr("e-d", ledger); break; case 'w': node = parse_expr("e-d"); break;
// Functions // Functions
case '-': case '-':
node = new node_t(F_NEG); node = new node_t(node_t::F_NEG);
node->left = parse_term(in, ledger); node->left = parse_term(in);
break; break;
case 'A': // absolute value ("positive") case 'A':
node = new node_t(F_ABS); node = new node_t(node_t::F_ABS);
node->left = parse_term(in, ledger); node->left = parse_term(in);
break; break;
case 'M': case 'M':
node = new node_t(F_ARITH_MEAN); node = new node_t(node_t::F_ARITH_MEAN);
node->left = parse_term(in, ledger); node->left = parse_term(in);
break; break;
case 'D': { case 'D': {
node = new node_t(O_SUB); node = new node_t(node_t::O_SUB);
node->left = parse_term("a", ledger); node->left = parse_term("a");
node->right = parse_term(in, ledger); node->right = parse_term(in);
break; break;
} }
case 'P': case 'P':
node = new node_t(F_VALUE); node = new node_t(node_t::F_VALUE);
if (in.peek() == '(') { if (in.peek() == '(') {
in.get(c); in.get(c);
node->left = parse_expr(in, ledger); node->left = parse_expr(in);
if (in.peek() == ',') { if (in.peek() == ',') {
in.get(c); in.get(c);
node->right = parse_expr(in, ledger); node->right = parse_expr(in);
} }
if (in.peek() == ')') if (in.peek() == ')')
in.get(c); in.get(c);
else else
throw expr_error("Missing ')'"); throw expr_error("Missing ')'");
} else { } else {
node->left = parse_term(in, ledger); node->left = parse_term(in);
} }
break; break;
@ -267,7 +267,7 @@ node_t * parse_term(std::istream& in, ledger_t * ledger)
} }
if (c == '/') { if (c == '/') {
in.get(c); in.get(c);
node = new node_t(F_REGEXP); node = new node_t(node_t::F_REGEXP);
node->mask = new mask_t(ident); node->mask = new mask_t(ident);
} else { } else {
throw expr_error("Missing closing '/'"); throw expr_error("Missing closing '/'");
@ -276,7 +276,7 @@ node_t * parse_term(std::istream& in, ledger_t * ledger)
} }
case '(': case '(':
node = parse_expr(in, ledger); node = parse_expr(in);
if (in.peek() == ')') if (in.peek() == ')')
in.get(c); in.get(c);
else else
@ -294,7 +294,7 @@ node_t * parse_term(std::istream& in, ledger_t * ledger)
} }
if (c == ']') { if (c == ']') {
in.get(c); in.get(c);
node = new node_t(CONSTANT_T); node = new node_t(node_t::CONSTANT_T);
if (! parse_date(ident.c_str(), &node->constant_t)) if (! parse_date(ident.c_str(), &node->constant_t))
throw expr_error("Failed to parse date"); throw expr_error("Failed to parse date");
} else { } else {
@ -311,11 +311,11 @@ node_t * parse_term(std::istream& in, ledger_t * ledger)
return node; return node;
} }
node_t * parse_mul_expr(std::istream& in, ledger_t * ledger) node_t * parse_mul_expr(std::istream& in)
{ {
node_t * node = NULL; node_t * node = NULL;
node = parse_term(in, ledger); node = parse_term(in);
if (node && ! in.eof()) { if (node && ! in.eof()) {
char c = in.peek(); char c = in.peek();
@ -324,17 +324,17 @@ node_t * parse_mul_expr(std::istream& in, ledger_t * ledger)
switch (c) { switch (c) {
case '*': { case '*': {
node_t * prev = node; node_t * prev = node;
node = new node_t(O_MUL); node = new node_t(node_t::O_MUL);
node->left = prev; node->left = prev;
node->right = parse_term(in, ledger); node->right = parse_term(in);
break; break;
} }
case '/': { case '/': {
node_t * prev = node; node_t * prev = node;
node = new node_t(O_DIV); node = new node_t(node_t::O_DIV);
node->left = prev; node->left = prev;
node->right = parse_term(in, ledger); node->right = parse_term(in);
break; break;
} }
} }
@ -345,11 +345,11 @@ node_t * parse_mul_expr(std::istream& in, ledger_t * ledger)
return node; return node;
} }
node_t * parse_add_expr(std::istream& in, ledger_t * ledger) node_t * parse_add_expr(std::istream& in)
{ {
node_t * node = NULL; node_t * node = NULL;
node = parse_mul_expr(in, ledger); node = parse_mul_expr(in);
if (node && ! in.eof()) { if (node && ! in.eof()) {
char c = in.peek(); char c = in.peek();
@ -358,17 +358,17 @@ node_t * parse_add_expr(std::istream& in, ledger_t * ledger)
switch (c) { switch (c) {
case '+': { case '+': {
node_t * prev = node; node_t * prev = node;
node = new node_t(O_ADD); node = new node_t(node_t::O_ADD);
node->left = prev; node->left = prev;
node->right = parse_mul_expr(in, ledger); node->right = parse_mul_expr(in);
break; break;
} }
case '-': { case '-': {
node_t * prev = node; node_t * prev = node;
node = new node_t(O_SUB); node = new node_t(node_t::O_SUB);
node->left = prev; node->left = prev;
node->right = parse_mul_expr(in, ledger); node->right = parse_mul_expr(in);
break; break;
} }
} }
@ -379,19 +379,19 @@ node_t * parse_add_expr(std::istream& in, ledger_t * ledger)
return node; return node;
} }
node_t * parse_logic_expr(std::istream& in, ledger_t * ledger) node_t * parse_logic_expr(std::istream& in)
{ {
node_t * node = NULL; node_t * node = NULL;
if (in.peek() == '!') { if (in.peek() == '!') {
char c; char c;
in.get(c); in.get(c);
node = new node_t(O_NOT); node = new node_t(node_t::O_NOT);
node->left = parse_logic_expr(in, ledger); node->left = parse_logic_expr(in);
return node; return node;
} }
node = parse_add_expr(in, ledger); node = parse_add_expr(in);
if (node && ! in.eof()) { if (node && ! in.eof()) {
char c = in.peek(); char c = in.peek();
@ -400,33 +400,33 @@ node_t * parse_logic_expr(std::istream& in, ledger_t * ledger)
switch (c) { switch (c) {
case '=': { case '=': {
node_t * prev = node; node_t * prev = node;
node = new node_t(O_EQ); node = new node_t(node_t::O_EQ);
node->left = prev; node->left = prev;
node->right = parse_add_expr(in, ledger); node->right = parse_add_expr(in);
break; break;
} }
case '<': { case '<': {
node_t * prev = node; node_t * prev = node;
node = new node_t(O_LT); node = new node_t(node_t::O_LT);
if (in.peek() == '=') { if (in.peek() == '=') {
in.get(c); in.get(c);
node->type = O_LTE; node->type = node_t::O_LTE;
} }
node->left = prev; node->left = prev;
node->right = parse_add_expr(in, ledger); node->right = parse_add_expr(in);
break; break;
} }
case '>': { case '>': {
node_t * prev = node; node_t * prev = node;
node = new node_t(O_GT); node = new node_t(node_t::O_GT);
if (in.peek() == '=') { if (in.peek() == '=') {
in.get(c); in.get(c);
node->type = O_GTE; node->type = node_t::O_GTE;
} }
node->left = prev; node->left = prev;
node->right = parse_add_expr(in, ledger); node->right = parse_add_expr(in);
break; break;
} }
@ -443,11 +443,11 @@ node_t * parse_logic_expr(std::istream& in, ledger_t * ledger)
return node; return node;
} }
node_t * parse_expr(std::istream& in, ledger_t * ledger) node_t * parse_expr(std::istream& in)
{ {
node_t * node = NULL; node_t * node = NULL;
node = parse_logic_expr(in, ledger); node = parse_logic_expr(in);
if (node && ! in.eof()) { if (node && ! in.eof()) {
char c = in.peek(); char c = in.peek();
@ -456,27 +456,27 @@ node_t * parse_expr(std::istream& in, ledger_t * ledger)
switch (c) { switch (c) {
case '&': { case '&': {
node_t * prev = node; node_t * prev = node;
node = new node_t(O_AND); node = new node_t(node_t::O_AND);
node->left = prev; node->left = prev;
node->right = parse_logic_expr(in, ledger); node->right = parse_logic_expr(in);
break; break;
} }
case '|': { case '|': {
node_t * prev = node; node_t * prev = node;
node = new node_t(O_OR); node = new node_t(node_t::O_OR);
node->left = prev; node->left = prev;
node->right = parse_logic_expr(in, ledger); node->right = parse_logic_expr(in);
break; break;
} }
case '?': { case '?': {
node_t * prev = node; node_t * prev = node;
node = new node_t(O_QUES); node = new node_t(node_t::O_QUES);
node->left = prev; node->left = prev;
node_t * choices = new node_t(O_COL); node_t * choices = new node_t(node_t::O_COL);
node->right = choices; node->right = choices;
choices->left = parse_logic_expr(in, ledger); choices->left = parse_logic_expr(in);
c = in.peek(); c = in.peek();
if (c != ':') { if (c != ':') {
std::ostringstream err; std::ostringstream err;
@ -484,7 +484,7 @@ node_t * parse_expr(std::istream& in, ledger_t * ledger)
throw expr_error(err.str()); throw expr_error(err.str());
} }
in.get(c); in.get(c);
choices->right = parse_logic_expr(in, ledger); choices->right = parse_logic_expr(in);
break; break;
} }
@ -512,43 +512,43 @@ namespace ledger {
static void dump_tree(std::ostream& out, node_t * node) static void dump_tree(std::ostream& out, node_t * node)
{ {
switch (node->type) { switch (node->type) {
case CONSTANT_A: out << "CONST[" << node->constant_a << "]"; break; case node_t::CONSTANT_A: out << "CONST[" << node->constant_a << "]"; break;
case CONSTANT_T: out << "DATE/TIME[" << node->constant_t << "]"; break; case node_t::CONSTANT_T: out << "DATE/TIME[" << node->constant_t << "]"; break;
case AMOUNT: out << "AMOUNT"; break; case node_t::AMOUNT: out << "AMOUNT"; break;
case COST: out << "COST"; break; case node_t::COST: out << "COST"; break;
case DATE: out << "DATE"; break; case node_t::DATE: out << "DATE"; break;
case INDEX: out << "INDEX"; break; case node_t::INDEX: out << "INDEX"; break;
case BALANCE: out << "BALANCE"; break; case node_t::BALANCE: out << "BALANCE"; break;
case COST_BALANCE: out << "COST_BALANCE"; break; case node_t::COST_BALANCE: out << "COST_BALANCE"; break;
case TOTAL: out << "TOTAL"; break; case node_t::TOTAL: out << "TOTAL"; break;
case COST_TOTAL: out << "COST_TOTAL"; break; case node_t::COST_TOTAL: out << "COST_TOTAL"; break;
case BEGIN_DATE: out << "BEGIN"; break; case node_t::BEGIN_DATE: out << "BEGIN"; break;
case END_DATE: out << "END"; break; case node_t::END_DATE: out << "END"; break;
case F_ARITH_MEAN: case node_t::F_ARITH_MEAN:
out << "MEAN("; out << "MEAN(";
dump_tree(out, node->left); dump_tree(out, node->left);
out << ")"; out << ")";
break; break;
case F_NEG: case node_t::F_NEG:
out << "ABS("; out << "ABS(";
dump_tree(out, node->left); dump_tree(out, node->left);
out << ")"; out << ")";
break; break;
case F_ABS: case node_t::F_ABS:
out << "ABS("; out << "ABS(";
dump_tree(out, node->left); dump_tree(out, node->left);
out << ")"; out << ")";
break; break;
case F_REGEXP: case node_t::F_REGEXP:
assert(node->mask); assert(node->mask);
out << "RE(" << node->mask->pattern << ")"; out << "RE(" << node->mask->pattern << ")";
break; break;
case F_VALUE: case node_t::F_VALUE:
out << "VALUE("; out << "VALUE(";
dump_tree(out, node->left); dump_tree(out, node->left);
if (node->right) { if (node->right) {
@ -558,12 +558,12 @@ static void dump_tree(std::ostream& out, node_t * node)
out << ")"; out << ")";
break; break;
case O_NOT: case node_t::O_NOT:
out << "!"; out << "!";
dump_tree(out, node->left); dump_tree(out, node->left);
break; break;
case O_QUES: case node_t::O_QUES:
dump_tree(out, node->left); dump_tree(out, node->left);
out << "?"; out << "?";
dump_tree(out, node->right->left); dump_tree(out, node->right->left);
@ -571,38 +571,38 @@ static void dump_tree(std::ostream& out, node_t * node)
dump_tree(out, node->right->right); dump_tree(out, node->right->right);
break; break;
case O_AND: case node_t::O_AND:
case O_OR: case node_t::O_OR:
case O_EQ: case node_t::O_EQ:
case O_LT: case node_t::O_LT:
case O_LTE: case node_t::O_LTE:
case O_GT: case node_t::O_GT:
case O_GTE: case node_t::O_GTE:
case O_ADD: case node_t::O_ADD:
case O_SUB: case node_t::O_SUB:
case O_MUL: case node_t::O_MUL:
case O_DIV: case node_t::O_DIV:
out << "("; out << "(";
dump_tree(out, node->left); dump_tree(out, node->left);
switch (node->type) { switch (node->type) {
case O_AND: out << " & "; break; case node_t::O_AND: out << " & "; break;
case O_OR: out << " | "; break; case node_t::O_OR: out << " | "; break;
case O_EQ: out << "="; break; case node_t::O_EQ: out << "="; break;
case O_LT: out << "<"; break; case node_t::O_LT: out << "<"; break;
case O_LTE: out << "<="; break; case node_t::O_LTE: out << "<="; break;
case O_GT: out << ">"; break; case node_t::O_GT: out << ">"; break;
case O_GTE: out << ">="; break; case node_t::O_GTE: out << ">="; break;
case O_ADD: out << "+"; break; case node_t::O_ADD: out << "+"; break;
case O_SUB: out << "-"; break; case node_t::O_SUB: out << "-"; break;
case O_MUL: out << "*"; break; case node_t::O_MUL: out << "*"; break;
case O_DIV: out << "/"; break; case node_t::O_DIV: out << "/"; break;
default: assert(0); break; default: assert(0); break;
} }
dump_tree(out, node->right); dump_tree(out, node->right);
out << ")"; out << ")";
break; break;
case LAST: case node_t::LAST:
default: default:
assert(0); assert(0);
break; break;

16
expr.h
View file

@ -7,6 +7,8 @@
namespace ledger { namespace ledger {
struct node_t
{
enum kind_t { enum kind_t {
// Constants // Constants
CONSTANT_A, CONSTANT_A,
@ -54,8 +56,6 @@ enum kind_t {
LAST LAST
}; };
struct node_t
{
kind_t type; kind_t type;
node_t * left; node_t * left;
node_t * right; node_t * right;
@ -78,18 +78,18 @@ struct node_t
const std::time_t end = -1) const; const std::time_t end = -1) const;
}; };
node_t * parse_expr(std::istream& in, ledger_t * ledger); node_t * parse_expr(std::istream& in);
inline node_t * parse_expr(const char * p, ledger_t * ledger) { inline node_t * parse_expr(const char * p) {
std::istringstream stream(p); std::istringstream stream(p);
return parse_expr(stream, ledger); return parse_expr(stream);
} }
inline node_t * parse_expr(const std::string& str, ledger_t * ledger) { inline node_t * parse_expr(const std::string& str) {
return parse_expr(str.c_str(), ledger); return parse_expr(str.c_str());
} }
inline node_t * find_node(node_t * node, kind_t type) { inline node_t * find_node(node_t * node, node_t::kind_t type) {
node_t * result = NULL; node_t * result = NULL;
if (node->type == type) if (node->type == type)
result = node; result = node;

201
format.cc
View file

@ -1,4 +1,5 @@
#include "format.h" #include "format.h"
#include "error.h"
namespace ledger { namespace ledger {
@ -24,20 +25,36 @@ std::string maximal_account_name(const item_t * item,
return name; return name;
} }
std::string format_t::report_line(const item_t * item, node_t * format_t::value_expr = NULL;
const item_t * displayed_parent) const node_t * format_t::total_expr = NULL;
{
std::string result;
for (const char * p = format_string.c_str(); *p; p++) { element_t * format_t::parse_elements(const std::string& fmt)
{
element_t * result = NULL;
element_t * current = NULL;
std::string str;
for (const char * p = fmt.c_str(); *p; p++) {
if (*p == '%') { if (*p == '%') {
bool leftalign = false; if (! result) {
int width = 0; current = result = new element_t;
int strict_width = 0; } else {
current->next = new element_t;
current = current->next;
}
if (! str.empty()) {
current->type = element_t::STRING;
current->chars = str;
str = "";
current->next = new element_t;
current = current->next;
}
++p; ++p;
if (*p == '-') { if (*p == '-') {
leftalign = true; current->align_left = true;
++p; ++p;
} }
@ -45,7 +62,7 @@ std::string format_t::report_line(const item_t * item,
while (*p && std::isdigit(*p)) while (*p && std::isdigit(*p))
num += *p++; num += *p++;
if (! num.empty()) if (! num.empty())
width = std::atol(num.c_str()); current->min_width = std::atol(num.c_str());
if (*p == '.') { if (*p == '.') {
++p; ++p;
@ -53,107 +70,149 @@ std::string format_t::report_line(const item_t * item,
while (*p && std::isdigit(*p)) while (*p && std::isdigit(*p))
num += *p++; num += *p++;
if (! num.empty()) { if (! num.empty()) {
strict_width = std::atol(num.c_str()); current->max_width = std::atol(num.c_str());
if (width == 0) if (current->min_width == 0)
width = strict_width; current->min_width = current->max_width;
} }
} }
std::ostringstream out;
if (leftalign)
out << std::left;
else
out << std::right;
if (width > 0)
out.width(width);
switch (*p) { switch (*p) {
case '%': case '%':
out << "%"; current->type = element_t::STRING;
current->chars = "%";
break; break;
case '(': { case '(':
++p; ++p;
num = ""; num = "";
while (*p && *p != ')') while (*p && *p != ')')
num += *p++; num += *p++;
assert(*p == ')'); if (*p != ')')
throw format_error("Missing ')'");
node_t * style = parse_expr(num, NULL); current->type = element_t::VALUE_EXPR;
balance_t value = style->compute(item); current->val_expr = parse_expr(num);
value.write(out, width, strict_width > 0 ? strict_width : width);
delete style;
break; break;
}
case '[': { case '[':
++p; ++p;
num = ""; num = "";
while (*p && *p != ']') while (*p && *p != ']')
num += *p++; num += *p++;
assert(*p == ']'); if (*p != ']')
throw format_error("Missing ']'");
current->type = element_t::DATE_STRING;
current->chars = num;
break;
case 'd':
current->type = element_t::DATE_STRING;
current->chars = "%Y/%m/%d";
break;
case 'p': current->type = element_t::PAYEE; break;
case 'n': current->type = element_t::ACCOUNT_NAME; break;
case 'N': current->type = element_t::ACCOUNT_FULLNAME; break;
case 't': current->type = element_t::VALUE; break;
case 'T': current->type = element_t::TOTAL; break;
case '_': current->type = element_t::SPACER; break;
}
} else {
str += *p;
}
}
if (! str.empty()) {
if (! result) {
current = result = new element_t;
} else {
current->next = new element_t;
current = current->next;
}
current->type = element_t::STRING;
current->chars = str;
}
return result;
}
void format_t::format_elements(std::ostream& out, const item_t * item,
const item_t * displayed_parent) const
{
std::string result;
for (const element_t * elem = elements;
elem;
elem = elem->next) {
if (elem->align_left)
out << std::left;
else
out << std::right;
if (elem->min_width > 0)
out.width(elem->min_width);
switch (elem->type) {
case element_t::STRING:
out << elem->chars;;
break;
case element_t::VALUE_EXPR: {
balance_t value = elem->val_expr->compute(item);
value.write(out, elem->min_width,
elem->max_width > 0 ? elem->max_width : elem->min_width);
break;
}
case element_t::DATE_STRING:
if (item->date != -1) { if (item->date != -1) {
char buf[256]; char buf[256];
std::strftime(buf, 255, num.c_str(), std::gmtime(&item->date)); std::strftime(buf, 255, elem->chars.c_str(), std::gmtime(&item->date));
out << (strict_width == 0 ? buf : truncated(buf, strict_width)); out << (elem->max_width == 0 ? buf : truncated(buf, elem->max_width));
} else { } else {
out << " "; out << " ";
} }
break; break;
}
case 'd': { case element_t::PAYEE:
if (item->date != -1) { out << (elem->max_width == 0 ?
char buf[32]; item->payee : truncated(item->payee, elem->max_width));
std::strftime(buf, 31, "%Y/%m/%d", std::gmtime(&item->date));
out << (strict_width == 0 ? buf : truncated(buf, strict_width));
} else {
out << " ";
}
break;
}
case 'p':
out << (strict_width == 0 ?
item->payee : truncated(item->payee, strict_width));
break; break;
case 'n': case element_t::ACCOUNT_NAME:
if (item->account) { if (item->account) {
std::string name = maximal_account_name(item, displayed_parent); std::string name = maximal_account_name(item, displayed_parent);
out << (strict_width == 0 ? name : truncated(name, strict_width)); out << (elem->max_width == 0 ? name : truncated(name, elem->max_width));
} else { } else {
out << " "; out << " ";
} }
break; break;
case 'N': case element_t::ACCOUNT_FULLNAME:
if (item->account) if (item->account)
out << (strict_width == 0 ? out << (elem->max_width == 0 ?
item->account->fullname() : item->account->fullname() :
truncated(item->account->fullname(), strict_width)); truncated(item->account->fullname(), elem->max_width));
else else
out << " "; out << " ";
break; break;
case 't': case element_t::VALUE: {
if (value_style) {
balance_t value = compute_value(item); balance_t value = compute_value(item);
value.write(out, width, strict_width > 0 ? strict_width : width); value.write(out, elem->min_width,
} elem->max_width > 0 ? elem->max_width : elem->min_width);
break; break;
}
case 'T': case element_t::TOTAL: {
if (total_style) {
balance_t value = compute_total(item); balance_t value = compute_total(item);
value.write(out, width, strict_width > 0 ? strict_width : width); value.write(out, elem->min_width,
} elem->max_width > 0 ? elem->max_width : elem->min_width);
break; break;
}
case '_': { case element_t::SPACER: {
int depth = 0; int depth = 0;
for (const item_t * i = item; i->parent; i = i->parent) for (const item_t * i = item; i->parent; i = i->parent)
depth++; depth++;
@ -164,21 +223,19 @@ std::string format_t::report_line(const item_t * item,
depth--; depth--;
while (--depth >= 0) { while (--depth >= 0) {
if (width > 0 || strict_width > 0) if (elem->min_width > 0 || elem->max_width > 0)
out.width(width > strict_width ? width : strict_width); out.width(elem->min_width > elem->max_width ?
elem->min_width : elem->max_width);
out << " "; out << " ";
} }
break; break;
} }
}
result += out.str(); default:
} else { assert(0);
result += *p; break;
} }
} }
return result;
} }
} // namespace ledger } // namespace ledger

View file

@ -11,56 +11,89 @@ namespace ledger {
std::string truncated(const std::string& str, unsigned int width); std::string truncated(const std::string& str, unsigned int width);
std::string maximal_account_name(const item_t * item, const item_t * parent); std::string maximal_account_name(const item_t * item, const item_t * parent);
struct element_t
{
enum kind_t {
STRING,
VALUE_EXPR,
DATE_STRING,
PAYEE,
ACCOUNT_NAME,
ACCOUNT_FULLNAME,
VALUE,
TOTAL,
SPACER
};
bool align_left;
unsigned int min_width;
unsigned int max_width;
kind_t type;
std::string chars;
node_t * val_expr;
struct element_t * next;
element_t() : align_left(false), min_width(0), max_width(0),
type(STRING), val_expr(NULL), next(NULL) {}
~element_t() {
if (val_expr) delete val_expr;
if (next) delete next; // recursive, but not too deep
}
};
struct format_t struct format_t
{ {
std::string format_string; element_t * elements;
node_t * value_style;
node_t * total_style;
format_t() { static node_t * value_expr;
value_style = NULL; static node_t * total_expr;
total_style = NULL;
format_t(const std::string& _format) {
elements = parse_elements(_format);
} }
~format_t() { ~format_t() {
if (value_style) delete value_style; if (elements) delete elements;
if (total_style) delete total_style;
} }
static element_t * parse_elements(const std::string& fmt);
void format_elements(std::ostream& out, const item_t * item,
const item_t * displayed_parent = NULL) const;
#if 1 #if 1
balance_t compute_value(const item_t * item) const { static balance_t compute_value(const item_t * item) {
if (value_style) if (value_expr)
return value_style->compute(item); return value_expr->compute(item);
else else
return balance_t(); return balance_t();
} }
balance_t compute_total(const item_t * item) const { static balance_t compute_total(const item_t * item) {
if (total_style) if (total_expr)
return total_style->compute(item); return total_expr->compute(item);
else else
return balance_t(); return balance_t();
} }
#else #else
balance_t compute_value(const item_t * item, static balance_t compute_value(const item_t * item,
const constraints_t& constraints) const { const constraints_t& constraints) {
if (value_style) if (value_expr)
return value_style->compute(item, constraints.begin(), constraints.end()); return value_expr->compute(item, constraints.begin(), constraints.end());
else else
return balance_t(); return balance_t();
} }
balance_t compute_total(const item_t * item, static balance_t compute_total(const item_t * item,
const constraints_t& constraints) const { const constraints_t& constraints) {
if (total_style) if (total_expr)
return total_style->compute(item, constraints.begin(), constraints.end()); return total_expr->compute(item, constraints.begin(), constraints.end());
else else
return balance_t(); return balance_t();
} }
#endif #endif
std::string report_line(const item_t * item,
const item_t * displayed_parent = NULL) const;
}; };
} // namespace ledger } // namespace ledger

View file

@ -113,7 +113,7 @@ static void endElement(void *userData, const char *name)
} }
else if (std::strcmp(name, "gnc:commodity") == 0) { else if (std::strcmp(name, "gnc:commodity") == 0) {
assert(curr_comm); assert(curr_comm);
curr_ledger->add_commodity(curr_comm); commodity_t::add_commodity(curr_comm);
curr_comm = NULL; curr_comm = NULL;
} }
else if (std::strcmp(name, "gnc:transaction") == 0) { else if (std::strcmp(name, "gnc:transaction") == 0) {
@ -166,9 +166,9 @@ static void dataHandler(void *userData, const char *s, int len)
if (curr_comm) if (curr_comm)
curr_comm->symbol = std::string(s, len); curr_comm->symbol = std::string(s, len);
else if (curr_account) else if (curr_account)
curr_account_comm = curr_ledger->find_commodity(std::string(s, len)); curr_account_comm = commodity_t::find_commodity(std::string(s, len));
else if (curr_entry) else if (curr_entry)
entry_comm = curr_ledger->find_commodity(std::string(s, len)); entry_comm = commodity_t::find_commodity(std::string(s, len));
break; break;
case COMM_NAME: case COMM_NAME:
@ -271,8 +271,8 @@ int parse_gnucash(std::istream& in, ledger_t * ledger, account_t * master)
// GnuCash uses the USD commodity without defining it, which really // GnuCash uses the USD commodity without defining it, which really
// means $. // means $.
commodity_t * usd = new commodity_t("$", 2, COMMODITY_STYLE_THOUSANDS); commodity_t * usd = new commodity_t("$", 2, COMMODITY_STYLE_THOUSANDS);
ledger->add_commodity(usd); commodity_t::add_commodity(usd);
ledger->add_commodity(usd, "USD"); commodity_t::add_commodity(usd, "USD");
XML_Parser parser = XML_ParserCreate(NULL); XML_Parser parser = XML_ParserCreate(NULL);
current_parser = parser; current_parser = parser;

View file

@ -12,7 +12,7 @@ item_t * walk_accounts(const account_t * account,
{ {
item_t * item = new item_t; item_t * item = new item_t;
item->account = account; item->account = account;
item->date = constraints.end(); item->date = constraints.end() - 1;
for (constrained_transactions_list_const_iterator for (constrained_transactions_list_const_iterator
i(account->transactions.begin(), i(account->transactions.begin(),
@ -112,6 +112,7 @@ item_t * walk_entries(entries_list::const_iterator begin,
item_t * subitem = new item_t; item_t * subitem = new item_t;
subitem->parent = item; subitem->parent = item;
subitem->date = item->date; subitem->date = item->date;
subitem->payee = item->payee;
subitem->account = (*j)->account; subitem->account = (*j)->account;
subitem->value = *(*j); subitem->value = *(*j);
item->subitems.push_back(subitem); item->subitems.push_back(subitem);
@ -125,6 +126,7 @@ item_t * walk_entries(entries_list::const_iterator begin,
item_t * subitem = new item_t; item_t * subitem = new item_t;
subitem->parent = item; subitem->parent = item;
subitem->date = item->date; subitem->date = item->date;
subitem->payee = item->payee;
subitem->account = (*k)->account; subitem->account = (*k)->account;
subitem->value = *(*k); subitem->value = *(*k);
if (constraints.show_inverted) if (constraints.show_inverted)

View file

@ -12,11 +12,6 @@ ledger_t::~ledger_t()
{ {
delete master; delete master;
for (commodities_map::iterator i = commodities.begin();
i != commodities.end();
i++)
delete (*i).second;
// Don't bother unhooking each entry's transactions from the // Don't bother unhooking each entry's transactions from the
// accounts they refer to, because all accounts are about to // accounts they refer to, because all accounts are about to
// be deleted. // be deleted.
@ -26,22 +21,6 @@ ledger_t::~ledger_t()
delete *i; delete *i;
} }
commodity_t * ledger_t::find_commodity(const std::string& symbol,
bool auto_create)
{
commodities_map::const_iterator i = commodities.find(symbol);
if (i != commodities.end())
return (*i).second;
if (auto_create) {
commodity_t * commodity = new commodity_t(symbol);
add_commodity(commodity);
return commodity;
}
return NULL;
}
bool ledger_t::add_entry(entry_t * entry) bool ledger_t::add_entry(entry_t * entry)
{ {
entries.push_back(entry); entries.push_back(entry);
@ -73,7 +52,7 @@ bool ledger_t::remove_entry(entry_t * entry)
return true; return true;
} }
int parse_ledger_file(char * p, ledger_t * book) int parse_ledger_file(char * p, ledger_t * journal)
{ {
char * sep = std::strrchr(p, '='); char * sep = std::strrchr(p, '=');
if (sep) *sep++ = '\0'; if (sep) *sep++ = '\0';
@ -82,11 +61,11 @@ int parse_ledger_file(char * p, ledger_t * book)
account_t * master; account_t * master;
if (sep) if (sep)
master = book->find_account(sep); master = journal->find_account(sep);
else else
master = book->master; master = journal->master;
book->sources.push_back(p); journal->sources.push_back(p);
unsigned long magic; unsigned long magic;
std::istream::pos_type start = stream.tellg(); std::istream::pos_type start = stream.tellg();
@ -94,9 +73,9 @@ int parse_ledger_file(char * p, ledger_t * book)
stream.seekg(start); stream.seekg(start);
if (magic == magic_number) if (magic == magic_number)
return read_binary_ledger(stream, "", book, master); return read_binary_ledger(stream, "", journal, master);
else else
return parse_textual_ledger(stream, book, master); return parse_textual_ledger(stream, journal, master);
} }
} // namespace ledger } // namespace ledger

View file

@ -50,8 +50,6 @@ class amount_t
base_type quantity; // amount, to MAX_PRECISION base_type quantity; // amount, to MAX_PRECISION
commodity_t * commodity; commodity_t * commodity;
static commodity_t * null_commodity;
bool valid() const { bool valid() const {
if (quantity) if (quantity)
return commodity != NULL; return commodity != NULL;
@ -185,10 +183,10 @@ class amount_t
operator std::string() const; operator std::string() const;
void parse(std::istream& in, ledger_t * ledger = NULL); void parse(std::istream& in);
void parse(const std::string& str, ledger_t * ledger = NULL) { void parse(const std::string& str) {
std::istringstream stream(str); std::istringstream stream(str);
parse(stream, ledger); parse(stream);
} }
void write_quantity(std::ostream& out) const; void write_quantity(std::ostream& out) const;
@ -223,6 +221,9 @@ std::ostream& operator<<(std::ostream& out, const amount_t& amt);
typedef std::map<const std::time_t, amount_t> history_map; typedef std::map<const std::time_t, amount_t> history_map;
typedef std::pair<const std::time_t, amount_t> history_pair; typedef std::pair<const std::time_t, amount_t> history_pair;
typedef std::map<const std::string, commodity_t *> commodities_map;
typedef std::pair<const std::string, commodity_t *> commodities_pair;
class commodity_t class commodity_t
{ {
public: public:
@ -235,11 +236,34 @@ class commodity_t
amount_t conversion; amount_t conversion;
unsigned long ident; unsigned long ident;
// If set, this global function pointer is called to determine
// whether prices have been updated in the meanwhile.
static void (*updater)(commodity_t * commodity, static void (*updater)(commodity_t * commodity,
const std::time_t date, const std::time_t date,
const amount_t& price, const amount_t& price,
const std::time_t moment); const std::time_t moment);
// This map remembers all commodities that have been
// defined thus far.
static commodities_map commodities;
static void add_commodity(commodity_t * commodity,
const std::string symbol = "") {
commodities.insert(commodities_pair((symbol.empty() ?
commodity->symbol : symbol),
commodity));
}
static bool remove_commodity(commodity_t * commodity) {
commodities_map::size_type n = commodities.erase(commodity->symbol);
return n > 0;
}
static commodity_t * find_commodity(const std::string& symbol,
bool auto_create = false);
// Now the per-object constructor and methods
commodity_t(const std::string& _symbol = "", commodity_t(const std::string& _symbol = "",
unsigned int _precision = 2, unsigned int _precision = 2,
unsigned int _flags = COMMODITY_STYLE_DEFAULTS) unsigned int _flags = COMMODITY_STYLE_DEFAULTS)
@ -377,17 +401,14 @@ inline std::ostream& operator<<(std::ostream& out, const account_t& acct) {
} }
typedef std::map<const std::string, commodity_t *> commodities_map;
typedef std::pair<const std::string, commodity_t *> commodities_pair;
typedef std::list<entry_t *> entries_list; typedef std::list<entry_t *> entries_list;
class ledger_t class ledger_t
{ {
public: public:
account_t * master; account_t * master;
commodities_map commodities;
entries_list entries; entries_list entries;
std::list<std::string> sources; std::list<std::string> sources;
ledger_t() { ledger_t() {
@ -409,23 +430,11 @@ class ledger_t
return master->find_account(name, auto_create); return master->find_account(name, auto_create);
} }
void add_commodity(commodity_t * commodity, const std::string symbol = "") {
commodities.insert(commodities_pair(symbol.empty() ?
commodity->symbol : symbol, commodity));
}
bool remove_commodity(commodity_t * commodity) {
commodities_map::size_type n = commodities.erase(commodity->symbol);
return n > 0;
}
commodity_t * find_commodity(const std::string& symbol,
bool auto_create = false);
bool add_entry(entry_t * entry); bool add_entry(entry_t * entry);
bool remove_entry(entry_t * entry); bool remove_entry(entry_t * entry);
}; };
int parse_ledger_file(char * p, ledger_t * book); int parse_ledger_file(char * p, ledger_t * journal);
} // namespace ledger } // namespace ledger

265
main.cc
View file

@ -48,7 +48,7 @@ void show_balances(std::ostream& out,
if (match && constraints(*i) && if (match && constraints(*i) &&
((*i)->subitems.size() != 1 || ((*i)->subitems.size() != 1 ||
(*i)->total != (*i)->subitems[0]->total)) { (*i)->total != (*i)->subitems[0]->total)) {
out << format.report_line(*i, parent); format.format_elements(out, *i, parent);
parent = *i; parent = *i;
} }
@ -69,9 +69,10 @@ void balance_report(std::ostream& out,
show_balances(out, top->subitems, constraints, format, top); show_balances(out, top->subitems, constraints, format, top);
if (constraints.show_subtotals && top->subitems.size() > 1 && top->total) if (constraints.show_subtotals && top->subitems.size() > 1 && top->total) {
std::cout << "--------------------\n" std::cout << "--------------------\n";
<< format.report_line(top); format.format_elements(std::cout, top);
}
} }
@ -81,7 +82,7 @@ void balance_report(std::ostream& out,
// //
static const std::string reg_fmt static const std::string reg_fmt
= "%10d %-.20p %/%-.22N %12.66t %12.80T\n"; = "%10d %-.20p %-.22N %12.66t %12.80T\n%/%22_ %-.22N %12.66t %12.80T\n";
static bool show_commodities_revalued = false; static bool show_commodities_revalued = false;
static bool show_commodities_revalued_only = false; static bool show_commodities_revalued_only = false;
@ -91,12 +92,10 @@ static void report_value_change(std::ostream& out,
const balance_pair_t& balance, const balance_pair_t& balance,
const balance_pair_t& prev_balance, const balance_pair_t& prev_balance,
const constraints_t& constraints, const constraints_t& constraints,
const format_t& format, const format_t& first_line_format,
const std::string& first_line_format, const format_t& next_lines_format)
const std::string& next_lines_format)
{ {
static std::time_t prev_date = -1; static std::time_t prev_date = -1;
if (prev_date == -1) { if (prev_date == -1) {
prev_date = date; prev_date = date;
return; return;
@ -105,11 +104,11 @@ static void report_value_change(std::ostream& out,
item_t temp; item_t temp;
temp.date = prev_date; temp.date = prev_date;
temp.total = prev_balance; temp.total = prev_balance;
balance_t prev_bal = format.compute_total(&temp); balance_t prev_bal = format_t::compute_total(&temp);
temp.date = date; temp.date = date;
temp.total = balance; temp.total = balance;
balance_t cur_bal = format.compute_total(&temp); balance_t cur_bal = format_t::compute_total(&temp);
if (balance_t diff = cur_bal - prev_bal) { if (balance_t diff = cur_bal - prev_bal) {
temp.value = diff; temp.value = diff;
@ -117,17 +116,8 @@ static void report_value_change(std::ostream& out,
temp.payee = "Commodities revalued"; temp.payee = "Commodities revalued";
if (constraints(&temp)) { if (constraints(&temp)) {
format_t copy = format; first_line_format.format_elements(out, &temp);
next_lines_format.format_elements(out, &temp);
copy.format_string = first_line_format;
out << copy.report_line(&temp);
copy.format_string = next_lines_format;
out << copy.report_line(&temp);
// Prevent double-deletion
copy.value_style = NULL;
copy.total_style = NULL;
} }
} }
@ -137,25 +127,12 @@ static void report_value_change(std::ostream& out,
void register_report(std::ostream& out, void register_report(std::ostream& out,
item_t * top, item_t * top,
const constraints_t& constraints, const constraints_t& constraints,
const format_t& format) const format_t& first_line_format,
const format_t& next_lines_format)
{ {
if (constraints.sort_order) if (constraints.sort_order)
top->sort(constraints.sort_order); top->sort(constraints.sort_order);
format_t copy = format;
std::string first_line_format;
std::string next_lines_format;
const char * f = format.format_string.c_str();
if (const char * p = std::strstr(f, "%/")) {
first_line_format = std::string(f, 0, p - f);
next_lines_format = std::string(p + 2);
} else {
first_line_format = format.format_string;
next_lines_format = format.format_string;
}
balance_pair_t balance; balance_pair_t balance;
balance_pair_t last_reported; balance_pair_t last_reported;
account_t splits(NULL, "<Total>"); account_t splits(NULL, "<Total>");
@ -163,13 +140,6 @@ void register_report(std::ostream& out,
for (items_deque::const_iterator i = top->subitems.begin(); for (items_deque::const_iterator i = top->subitems.begin();
i != top->subitems.end(); i != top->subitems.end();
i++) { i++) {
copy.format_string = first_line_format;
std::string header = copy.report_line(*i, top);
unsigned int header_len = header.length();
copy.format_string = next_lines_format;
bool first = true; bool first = true;
if ((*i)->subitems.size() > 1 && ! constraints.show_expanded) { if ((*i)->subitems.size() > 1 && ! constraints.show_expanded) {
@ -187,14 +157,14 @@ void register_report(std::ostream& out,
bool show = constraints(&summary); bool show = constraints(&summary);
if (show && show_commodities_revalued) if (show && show_commodities_revalued)
report_value_change(out, summary.date, balance, last_reported, report_value_change(out, summary.date, balance, last_reported,
constraints, copy, first_line_format, constraints, first_line_format, next_lines_format);
next_lines_format);
balance += summary.value; balance += summary.value;
if (show) { if (show) {
if (! show_commodities_revalued_only) if (! show_commodities_revalued_only)
out << header << copy.report_line(&summary, *i); first_line_format.format_elements(out, *i, top);
if (show_commodities_revalued) if (show_commodities_revalued)
last_reported = balance; last_reported = balance;
} }
@ -207,7 +177,7 @@ void register_report(std::ostream& out,
bool show = constraints(*j); bool show = constraints(*j);
if (show && first && show_commodities_revalued) { if (show && first && show_commodities_revalued) {
report_value_change(out, (*i)->date, balance, last_reported, report_value_change(out, (*i)->date, balance, last_reported,
constraints, copy, first_line_format, constraints, first_line_format,
next_lines_format); next_lines_format);
if (show_commodities_revalued_only) if (show_commodities_revalued_only)
first = false; first = false;
@ -219,13 +189,12 @@ void register_report(std::ostream& out,
if (! show_commodities_revalued_only) { if (! show_commodities_revalued_only) {
if (first) { if (first) {
first = false; first = false;
out << header; first_line_format.format_elements(out, *j, *i);
} else { } else {
out.width(header_len); next_lines_format.format_elements(out, *j, *i);
out << " ";
} }
out << copy.report_line(*j, *i);
} }
if (show_commodities_revalued) if (show_commodities_revalued)
last_reported = balance; last_reported = balance;
} }
@ -235,12 +204,7 @@ void register_report(std::ostream& out,
if (show_commodities_revalued) if (show_commodities_revalued)
report_value_change(out, constraints.end(), balance, last_reported, report_value_change(out, constraints.end(), balance, last_reported,
constraints, copy, first_line_format, constraints, first_line_format, next_lines_format);
next_lines_format);
// To stop these from getting deleted when copy goes out of scope
copy.value_style = NULL;
copy.total_style = NULL;
} }
@ -377,7 +341,7 @@ bool add_new_entry(int index, int argc, char **argv, ledger_t * ledger)
} }
void set_price_conversion(const std::string& setting, ledger_t * ledger) void set_price_conversion(const std::string& setting)
{ {
char buf[128]; char buf[128];
std::strcpy(buf, setting.c_str()); std::strcpy(buf, setting.c_str());
@ -392,9 +356,9 @@ void set_price_conversion(const std::string& setting, ledger_t * ledger)
*p++ = '\0'; *p++ = '\0';
amount_t price; amount_t price;
price.parse(p, ledger); price.parse(p);
commodity_t * commodity = ledger->find_commodity(c, true); commodity_t * commodity = commodity_t::find_commodity(c, true);
commodity->set_conversion(price); commodity->set_conversion(price);
} }
} }
@ -402,7 +366,6 @@ void set_price_conversion(const std::string& setting, ledger_t * ledger)
static long pricing_leeway = 24 * 3600; static long pricing_leeway = 24 * 3600;
static std::string price_db; static std::string price_db;
static ledger_t * current_ledger = NULL;
static bool cache_dirty = false; static bool cache_dirty = false;
void download_price_quote(commodity_t * commodity, void download_price_quote(commodity_t * commodity,
@ -438,7 +401,7 @@ void download_price_quote(commodity_t * commodity,
if (p) *p = '\0'; if (p) *p = '\0';
amount_t current; amount_t current;
current.parse(buf, current_ledger); current.parse(buf);
commodity->add_price(now, current); commodity->add_price(now, current);
@ -506,13 +469,12 @@ static void show_help(std::ostream& out)
int main(int argc, char * argv[]) int main(int argc, char * argv[])
{ {
std::list<std::string> files; std::list<std::string> files;
ledger::ledger_t * book = new ledger::ledger_t; ledger::ledger_t * journal = new ledger::ledger_t;
ledger::constraints_t constraints; ledger::constraints_t constraints;
ledger::format_t format; std::string format_string;
std::string sort_order; std::string sort_order;
std::string value_style = "a"; std::string value_expr = "a";
std::string total_style = "T"; std::string total_expr = "T";
// Initialize some variables based on environment variable settings // Initialize some variables based on environment variable settings
@ -540,19 +502,17 @@ int main(int argc, char * argv[])
if (access(p, R_OK) != -1) { if (access(p, R_OK) != -1) {
std::ifstream instr(p); std::ifstream instr(p);
if (! ledger::read_binary_ledger(instr, std::getenv("LEDGER"), if (! ledger::read_binary_ledger(instr, std::getenv("LEDGER"),
book)) { journal)) {
// We need to throw away what we've read, and create a new // We need to throw away what we've read, and create a new
// ledger // ledger
delete book; delete journal;
book = new ledger::ledger_t; journal = new ledger::ledger_t;
} else { } else {
ledger::cache_dirty = false; ledger::cache_dirty = false;
} }
} }
} }
ledger::current_ledger = book;
// Parse the command-line options // Parse the command-line options
int c, index; int c, index;
@ -584,7 +544,7 @@ int main(int argc, char * argv[])
break; break;
case 'p': case 'p':
ledger::set_price_conversion(optarg, book); ledger::set_price_conversion(optarg);
break; break;
// Constraint options // Constraint options
@ -593,7 +553,6 @@ int main(int argc, char * argv[])
break; break;
case 'b': case 'b':
constraints.have_beginning = true;
if (! ledger::parse_date(optarg, &constraints.begin_date)) { if (! ledger::parse_date(optarg, &constraints.begin_date)) {
std::cerr << "Error: Bad begin date: " << optarg << std::endl; std::cerr << "Error: Bad begin date: " << optarg << std::endl;
return 1; return 1;
@ -601,7 +560,6 @@ int main(int argc, char * argv[])
break; break;
case 'e': case 'e':
constraints.have_ending = true;
if (! ledger::parse_date(optarg, &constraints.end_date)) { if (! ledger::parse_date(optarg, &constraints.end_date)) {
std::cerr << "Error: Bad end date: " << optarg << std::endl; std::cerr << "Error: Bad end date: " << optarg << std::endl;
return 1; return 1;
@ -610,7 +568,6 @@ int main(int argc, char * argv[])
case 'c': case 'c':
constraints.end_date = std::time(NULL); constraints.end_date = std::time(NULL);
constraints.have_ending = true;
break; break;
case 'd': case 'd':
@ -635,7 +592,7 @@ int main(int argc, char * argv[])
// Customizing output // Customizing output
case 'F': case 'F':
format.format_string = optarg; format_string = optarg;
break; break;
case 'M': case 'M':
@ -663,7 +620,7 @@ int main(int argc, char * argv[])
break; break;
case 'l': case 'l':
constraints.predicate = ledger::parse_expr(optarg, book); constraints.predicate = ledger::parse_expr(optarg);
break; break;
// Commodity reporting // Commodity reporting
@ -680,61 +637,61 @@ int main(int argc, char * argv[])
break; break;
case 't': case 't':
value_style = optarg; value_expr = optarg;
break; break;
case 'T': case 'T':
total_style = optarg; total_expr = optarg;
break; break;
case 'O': case 'O':
value_style = "a"; value_expr = "a";
total_style = "T"; total_expr = "T";
break; break;
case 'B': case 'B':
value_style = "c"; value_expr = "c";
total_style = "C"; total_expr = "C";
break; break;
case 'V': case 'V':
ledger::show_commodities_revalued = true; ledger::show_commodities_revalued = true;
value_style = "v"; value_expr = "v";
total_style = "V"; total_expr = "V";
break; break;
case 'G': case 'G':
ledger::show_commodities_revalued = ledger::show_commodities_revalued =
ledger::show_commodities_revalued_only = true; ledger::show_commodities_revalued_only = true;
value_style = "c"; value_expr = "c";
total_style = "G"; total_expr = "G";
break; break;
case 'A': case 'A':
value_style = "a"; value_expr = "a";
total_style = "MT"; total_expr = "MT";
break; break;
case 'D': case 'D':
value_style = "a"; value_expr = "a";
total_style = "DMT"; total_expr = "DMT";
break; break;
case 'Z': case 'Z':
value_style = "a"; value_expr = "a";
total_style = "MDMT"; total_expr = "MDMT";
break; break;
case 'W': case 'W':
value_style = "a"; value_expr = "a";
total_style = "MD(MT*(d-b/e-b))"; total_expr = "MD(MT*(d-b/e-b))";
break; break;
case 'X': case 'X':
value_style = "a"; value_expr = "a";
total_style = "a+MD(MT*(d-b/e-b))"; total_expr = "a+MD(MT*(d-b/e-b))";
break; break;
} }
} }
@ -755,14 +712,14 @@ int main(int argc, char * argv[])
if (files.empty()) { if (files.empty()) {
if (char * p = std::getenv("LEDGER")) if (char * p = std::getenv("LEDGER"))
for (p = std::strtok(p, ":"); p; p = std::strtok(NULL, ":")) for (p = std::strtok(p, ":"); p; p = std::strtok(NULL, ":"))
entry_count += parse_ledger_file(p, book); entry_count += parse_ledger_file(p, journal);
} else { } else {
for (std::list<std::string>::iterator i = files.begin(); for (std::list<std::string>::iterator i = files.begin();
i != files.end(); i++) { i != files.end(); i++) {
char buf[4096]; char buf[4096];
char * p = buf; char * p = buf;
std::strcpy(p, (*i).c_str()); std::strcpy(p, (*i).c_str());
entry_count += parse_ledger_file(p, book); entry_count += parse_ledger_file(p, journal);
} }
} }
@ -772,8 +729,8 @@ int main(int argc, char * argv[])
if (! ledger::price_db.empty()) { if (! ledger::price_db.empty()) {
const char * path = ledger::price_db.c_str(); const char * path = ledger::price_db.c_str();
std::ifstream db(path); std::ifstream db(path);
book->sources.push_back(path); journal->sources.push_back(path);
entry_count += ledger::parse_textual_ledger(db, book, book->master); entry_count += ledger::parse_textual_ledger(db, journal, journal->master);
} }
} }
catch (ledger::error& err) { catch (ledger::error& err) {
@ -794,7 +751,7 @@ int main(int argc, char * argv[])
const std::string command = argv[index++]; const std::string command = argv[index++];
if (command == "entry") if (command == "entry")
return add_new_entry(index, argc, argv, book) ? 0 : 1; return add_new_entry(index, argc, argv, journal) ? 0 : 1;
// Interpret the remaining arguments as regular expressions, used // Interpret the remaining arguments as regular expressions, used
// for refining report results. // for refining report results.
@ -814,77 +771,100 @@ int main(int argc, char * argv[])
// and total style strings // and total style strings
if (! sort_order.empty()) if (! sort_order.empty())
constraints.sort_order = ledger::parse_expr(sort_order, book); constraints.sort_order = ledger::parse_expr(sort_order);
format.value_style = ledger::parse_expr(value_style, book);
format.total_style = ledger::parse_expr(total_style, book); // Setup the meaning of %t and %T encountered in format strings
ledger::format_t::value_expr = ledger::parse_expr(value_expr);
ledger::format_t::total_expr = ledger::parse_expr(total_expr);
// Now handle the command that was identified above. // Now handle the command that was identified above.
if (command == "print") { if (command == "print") {
#if 0 #if 0
ledger::item_t * top if (ledger::item_t * top
= ledger::walk_entries(book->entries.begin(), book->entries.end(), = ledger::walk_entries(journal->entries.begin(),
constraints, format); journal->entries.end(),
ledger::entry_report(std::cout, top, format); constraints)) {
ledger::format_t * format = new ledger::format_t(format_string);
ledger::entry_report(std::cout, top, *format);
#ifdef DEBUG #ifdef DEBUG
delete top; delete top;
delete format;
#endif #endif
}
#endif #endif
} }
else if (command == "equity") { else if (command == "equity") {
#if 0 #if 0
ledger::item_t * top if (ledger::item_t * top
= ledger::walk_accounts(book->master, constraints); = ledger::walk_accounts(journal->master, constraints)) {
ledger::format_t * format = new ledger::format_t(format_string);
ledger::entry_report(std::cout, top, constraints, format); ledger::entry_report(std::cout, top, constraints, *format);
#ifdef DEBUG #ifdef DEBUG
delete top; delete top;
delete format;
#endif #endif
}
#endif #endif
} }
else if (constraints.period == ledger::PERIOD_NONE && else if (constraints.period == ledger::PERIOD_NONE &&
! constraints.sort_order && ! constraints.show_related && ! constraints.sort_order && ! constraints.show_related &&
(command == "balance" || command == "bal")) { (command == "balance" || command == "bal")) {
if (format.format_string.empty())
format.format_string = ledger::bal_fmt;
if (ledger::item_t * top if (ledger::item_t * top
= ledger::walk_accounts(book->master, constraints)) { = ledger::walk_accounts(journal->master, constraints)) {
ledger::balance_report(std::cout, top, constraints, format); ledger::format_t * format
= new ledger::format_t(format_string.empty() ?
ledger::bal_fmt : format_string);
ledger::balance_report(std::cout, top, constraints, *format);
#ifdef DEBUG #ifdef DEBUG
delete format;
delete top; delete top;
#endif #endif
} }
} }
else if (command == "balance" || command == "bal") { else if (command == "balance" || command == "bal") {
if (format.format_string.empty())
format.format_string = ledger::bal_fmt;
if (ledger::item_t * list if (ledger::item_t * list
= ledger::walk_entries(book->entries.begin(), = ledger::walk_entries(journal->entries.begin(),
book->entries.end(), constraints)) journal->entries.end(), constraints))
if (ledger::item_t * top if (ledger::item_t * top
= ledger::walk_items(list, book->master, constraints)) { = ledger::walk_items(list, journal->master, constraints)) {
ledger::balance_report(std::cout, top, constraints, format); ledger::format_t * format
= new ledger::format_t(format_string.empty() ?
ledger::bal_fmt : format_string);
ledger::balance_report(std::cout, top, constraints, *format);
#ifdef DEBUG #ifdef DEBUG
delete format;
delete top; delete top;
delete list; delete list;
#endif #endif
} }
} }
else if (command == "register" || command == "reg") { else if (command == "register" || command == "reg") {
if (format.format_string.empty())
format.format_string = ledger::reg_fmt;
if (constraints.show_related) if (constraints.show_related)
constraints.show_inverted = true; constraints.show_inverted = true;
if (ledger::item_t * top if (ledger::item_t * top
= ledger::walk_entries(book->entries.begin(), = ledger::walk_entries(journal->entries.begin(),
book->entries.end(), constraints)) { journal->entries.end(), constraints)) {
ledger::register_report(std::cout, top, constraints, format); std::string first_line_format;
std::string next_lines_format;
const char * f = (format_string.empty() ?
ledger::reg_fmt.c_str() : format_string.c_str());
if (const char * p = std::strstr(f, "%/")) {
first_line_format = std::string(f, 0, p - f);
next_lines_format = std::string(p + 2);
} else {
first_line_format = format_string;
next_lines_format = format_string;
}
ledger::format_t * format = new ledger::format_t(first_line_format);
ledger::format_t * nformat = new ledger::format_t(next_lines_format);
ledger::register_report(std::cout, top, constraints, *format, *nformat);
#ifdef DEBUG #ifdef DEBUG
delete format;
delete top; delete top;
#endif #endif
} }
@ -901,11 +881,24 @@ int main(int argc, char * argv[])
if (const char * p = std::getenv("LEDGER_CACHE")) { if (const char * p = std::getenv("LEDGER_CACHE")) {
std::ofstream outstr(p); std::ofstream outstr(p);
assert(std::getenv("LEDGER")); assert(std::getenv("LEDGER"));
ledger::write_binary_ledger(outstr, book, std::getenv("LEDGER")); ledger::write_binary_ledger(outstr, journal, std::getenv("LEDGER"));
} }
#ifdef DEBUG #ifdef DEBUG
delete book; delete journal;
if (ledger::format_t::value_expr)
delete ledger::format_t::value_expr;
if (ledger::format_t::total_expr)
delete ledger::format_t::total_expr;
// jww (2004-07-30): This should be moved into some kind of
// "ledger::shutdown" function.
for (ledger::commodities_map::iterator i
= ledger::commodity_t::commodities.begin();
i != ledger::commodity_t::commodities.end();
i++)
delete (*i).second;
#endif #endif
return 0; return 0;

View file

@ -186,8 +186,8 @@ inline char peek_next_nonws(std::istream& in)
return c; return c;
} }
transaction_t * parse_transaction_text(char * line, ledger_t * ledger, transaction_t * parse_transaction_text(char * line, account_t * account,
account_t * account, entry_t * entry) entry_t * entry)
{ {
// The account will be determined later... // The account will be determined later...
@ -208,10 +208,10 @@ transaction_t * parse_transaction_text(char * line, ledger_t * ledger,
char * price_str = std::strchr(cost_str, '@'); char * price_str = std::strchr(cost_str, '@');
if (price_str) { if (price_str) {
*price_str++ = '\0'; *price_str++ = '\0';
xact->cost.parse(price_str, ledger); xact->cost.parse(price_str);
} }
xact->amount.parse(cost_str, ledger); xact->amount.parse(cost_str);
if (price_str) if (price_str)
xact->cost *= xact->amount; xact->cost *= xact->amount;
@ -233,21 +233,21 @@ transaction_t * parse_transaction_text(char * line, ledger_t * ledger,
xact->account = account->find_account(p); xact->account = account->find_account(p);
if (! xact->amount.commodity) if (! xact->amount.commodity)
xact->amount.commodity = ledger->find_commodity("", true); xact->amount.commodity = commodity_t::find_commodity("", true);
if (! xact->cost.commodity) if (! xact->cost.commodity)
xact->cost.commodity = ledger->find_commodity("", true); xact->cost.commodity = commodity_t::find_commodity("", true);
return xact; return xact;
} }
transaction_t * parse_transaction(std::istream& in, ledger_t * ledger, transaction_t * parse_transaction(std::istream& in, account_t * account,
account_t * account, entry_t * entry) entry_t * entry)
{ {
static char line[MAX_LINE + 1]; static char line[MAX_LINE + 1];
in.getline(line, MAX_LINE); in.getline(line, MAX_LINE);
linenum++; linenum++;
return parse_transaction_text(line, ledger, account, entry); return parse_transaction_text(line, account, entry);
} }
class automated_transaction_t class automated_transaction_t
@ -338,8 +338,7 @@ public:
} }
}; };
void parse_automated_transactions(std::istream& in, ledger_t * ledger, void parse_automated_transactions(std::istream& in, account_t * account,
account_t * account,
automated_transactions_t& auto_xacts) automated_transactions_t& auto_xacts)
{ {
static char line[MAX_LINE + 1]; static char line[MAX_LINE + 1];
@ -359,7 +358,7 @@ void parse_automated_transactions(std::istream& in, ledger_t * ledger,
transactions_list xacts; transactions_list xacts;
while (! in.eof() && (in.peek() == ' ' || in.peek() == '\t')) { while (! in.eof() && (in.peek() == ' ' || in.peek() == '\t')) {
if (transaction_t * xact = parse_transaction(in, ledger, account, NULL)) { if (transaction_t * xact = parse_transaction(in, account, NULL)) {
if (! xact->amount) if (! xact->amount)
throw parse_error(path, linenum, throw parse_error(path, linenum,
"All automated transactions must have a value"); "All automated transactions must have a value");
@ -446,8 +445,7 @@ bool finalize_entry(entry_t * entry)
return ! balance; return ! balance;
} }
entry_t * parse_entry(std::istream& in, ledger_t * ledger, entry_t * parse_entry(std::istream& in, account_t * master)
account_t * master)
{ {
entry_t * curr = new entry_t; entry_t * curr = new entry_t;
@ -486,7 +484,7 @@ entry_t * parse_entry(std::istream& in, ledger_t * ledger,
// Parse all of the transactions associated with this entry // Parse all of the transactions associated with this entry
while (! in.eof() && (in.peek() == ' ' || in.peek() == '\t')) while (! in.eof() && (in.peek() == ' ' || in.peek() == '\t'))
if (transaction_t * xact = parse_transaction(in, ledger, master, curr)) if (transaction_t * xact = parse_transaction(in, master, curr))
curr->add_transaction(xact); curr->add_transaction(xact);
// If there were no transactions, throw away the entry // If there were no transactions, throw away the entry
@ -504,7 +502,7 @@ entry_t * parse_entry(std::istream& in, ledger_t * ledger,
// Textual ledger parser // Textual ledger parser
// //
unsigned int parse_textual_ledger(std::istream& in, ledger_t * ledger, unsigned int parse_textual_ledger(std::istream& in, ledger_t * journal,
account_t * master) account_t * master)
{ {
static char line[MAX_LINE + 1]; static char line[MAX_LINE + 1];
@ -517,11 +515,11 @@ unsigned int parse_textual_ledger(std::istream& in, ledger_t * ledger,
automated_transactions_t auto_xacts; automated_transactions_t auto_xacts;
if (! master) if (! master)
master = ledger->master; master = journal->master;
account_stack.push_front(master); account_stack.push_front(master);
path = ledger->sources.back(); path = journal->sources.back();
linenum = 1; linenum = 1;
while (! in.eof()) { while (! in.eof()) {
@ -602,14 +600,14 @@ unsigned int parse_textual_ledger(std::istream& in, ledger_t * ledger,
char buf[32]; char buf[32];
std::sprintf(buf, "%fh", diff); std::sprintf(buf, "%fh", diff);
amount_t amt; amount_t amt;
amt.parse(buf, ledger); amt.parse(buf);
time_commodity = amt.commodity; time_commodity = amt.commodity;
transaction_t * xact = new transaction_t(curr, last_account, amt, amt, transaction_t * xact = new transaction_t(curr, last_account, amt, amt,
TRANSACTION_VIRTUAL); TRANSACTION_VIRTUAL);
curr->add_transaction(xact); curr->add_transaction(xact);
if (! finalize_entry(curr) || ! ledger->add_entry(curr)) if (! finalize_entry(curr) || ! journal->add_entry(curr))
assert(0); assert(0);
count++; count++;
@ -650,9 +648,9 @@ unsigned int parse_textual_ledger(std::istream& in, ledger_t * ledger,
parse_commodity(in, symbol); parse_commodity(in, symbol);
in >> line; // the price in >> line; // the price
price.parse(line, ledger); price.parse(line);
commodity_t * commodity = ledger->find_commodity(symbol, true); commodity_t * commodity = commodity_t::find_commodity(symbol, true);
commodity->add_price(date, price); commodity->add_price(date, price);
break; break;
} }
@ -663,7 +661,7 @@ unsigned int parse_textual_ledger(std::istream& in, ledger_t * ledger,
in >> c; in >> c;
parse_commodity(in, symbol); parse_commodity(in, symbol);
commodity_t * commodity = ledger->find_commodity(line, true); commodity_t * commodity = commodity_t::find_commodity(line, true);
commodity->flags |= (COMMODITY_STYLE_CONSULTED | commodity->flags |= (COMMODITY_STYLE_CONSULTED |
COMMODITY_STYLE_NOMARKET); COMMODITY_STYLE_NOMARKET);
break; break;
@ -677,9 +675,9 @@ unsigned int parse_textual_ledger(std::istream& in, ledger_t * ledger,
parse_commodity(in, symbol); parse_commodity(in, symbol);
in >> line; // the price in >> line; // the price
price.parse(line, ledger); price.parse(line);
commodity_t * commodity = ledger->find_commodity(symbol, true); commodity_t * commodity = commodity_t::find_commodity(symbol, true);
commodity->set_conversion(price); commodity->set_conversion(price);
break; break;
} }
@ -700,8 +698,7 @@ unsigned int parse_textual_ledger(std::istream& in, ledger_t * ledger,
break; break;
case '=': // automated transactions case '=': // automated transactions
parse_automated_transactions(in, ledger, account_stack.front(), parse_automated_transactions(in, account_stack.front(), auto_xacts);
auto_xacts);
break; break;
case '@': { // account specific case '@': { // account specific
@ -729,12 +726,12 @@ unsigned int parse_textual_ledger(std::istream& in, ledger_t * ledger,
char * p = skip_ws(line); char * p = skip_ws(line);
std::ifstream stream(p); std::ifstream stream(p);
ledger->sources.push_back(p); journal->sources.push_back(p);
unsigned int curr_linenum = linenum; unsigned int curr_linenum = linenum;
std::string curr_path = path; std::string curr_path = path;
count += parse_textual_ledger(stream, ledger, account_stack.front()); count += parse_textual_ledger(stream, journal, account_stack.front());
linenum = curr_linenum; linenum = curr_linenum;
path = curr_path; path = curr_path;
@ -743,11 +740,11 @@ unsigned int parse_textual_ledger(std::istream& in, ledger_t * ledger,
default: { default: {
unsigned int first_line = linenum; unsigned int first_line = linenum;
if (entry_t * entry = parse_entry(in, ledger, account_stack.front())) { if (entry_t * entry = parse_entry(in, account_stack.front())) {
if (! auto_xacts.automated_transactions.empty()) if (! auto_xacts.automated_transactions.empty())
auto_xacts.extend_entry(entry); auto_xacts.extend_entry(entry);
if (ledger->add_entry(entry)) if (journal->add_entry(entry))
count++; count++;
else else
throw parse_error(path, first_line, "Entry does not balance"); throw parse_error(path, first_line, "Entry does not balance");
@ -876,11 +873,11 @@ void print_textual_entry(std::ostream& out, entry_t * entry, bool shortcut)
out << std::endl; out << std::endl;
} }
void print_textual_ledger(std::ostream& out, ledger_t * ledger, void print_textual_ledger(std::ostream& out, ledger_t * journal,
bool shortcut) bool shortcut)
{ {
for (entries_list::const_iterator i = ledger->entries.begin(); for (entries_list::const_iterator i = journal->entries.begin();
i != ledger->entries.end(); i != journal->entries.end();
i++) i++)
print_textual_entry(out, *i, shortcut); print_textual_entry(out, *i, shortcut);
} }
@ -891,12 +888,12 @@ void print_textual_ledger(std::ostream& out, ledger_t * ledger,
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
book.sources.push_back(argv[1]); journal.sources.push_back(argv[1]);
std::ifstream stream(argv[1]); std::ifstream stream(argv[1]);
ledger::ledger_t book; ledger::ledger_t journal;
int count = parse_textual_ledger(stream, &book, book.master); int count = parse_textual_ledger(stream, &journal, journal.master);
std::cout << "Read " << count << " entries." << std::endl; std::cout << "Read " << count << " entries." << std::endl;
print_textual_ledger(std::cout, &book, true); print_textual_ledger(std::cout, &journal, true);
} }
#endif // PARSE_TEST #endif // PARSE_TEST