further reorganization

This commit is contained in:
John Wiegley 2004-07-27 02:23:02 -04:00
parent dd5680c267
commit d7dd02276c
5 changed files with 230 additions and 242 deletions

View file

@ -200,6 +200,10 @@ bool constraints_t::operator ()(const item_t * item) const
return false; return false;
#if 0 #if 0
// jww (2004-07-26): It shouldn't be necessary to check against the
// account here, since this is always done during initial compiling
// of the item_t tree.
if (! account_masks.empty()) { if (! account_masks.empty()) {
bool match = false; bool match = false;

37
item.cc
View file

@ -8,8 +8,7 @@ namespace ledger {
// subaccounts, empty balanced or no // subaccounts, empty balanced or no
item_t * walk_accounts(const account_t * account, item_t * walk_accounts(const account_t * account,
const constraints_t& constraints, const constraints_t& constraints)
const bool compute_subtotals)
{ {
item_t * item = new item_t; item_t * item = new item_t;
item->account = account; item->account = account;
@ -21,64 +20,60 @@ item_t * walk_accounts(const account_t * account,
i != account->transactions.end(); i != account->transactions.end();
i++) { i++) {
item->value += *(*i); item->value += *(*i);
if (compute_subtotals) if (constraints.show_subtotals)
item->total += *(*i); item->total += *(*i);
} }
for (accounts_map::const_iterator i = account->accounts.begin(); for (accounts_map::const_iterator i = account->accounts.begin();
i != account->accounts.end(); i != account->accounts.end();
i++) { i++) {
item_t * subitem = walk_accounts((*i).second, constraints, item_t * subitem = walk_accounts((*i).second, constraints);
compute_subtotals);
subitem->parent = item; subitem->parent = item;
if (compute_subtotals) if (constraints.show_subtotals)
item->total += subitem->total; item->total += subitem->total;
if (compute_subtotals ? subitem->total : subitem->value) if (constraints.show_subtotals ? subitem->total : subitem->value)
item->subitems.push_back(subitem); item->subitems.push_back(subitem);
} }
return item; return item;
} }
static inline void sum_items(const item_t * top, static inline void sum_items(const item_t * top,
item_t * item, const constraints_t& constraints,
const bool compute_subtotals) item_t * item)
{ {
if (top->account == item->account) { if (top->account == item->account) {
item->value += top->value; item->value += top->value;
if (compute_subtotals) if (constraints.show_subtotals)
item->total += top->value; item->total += top->value;
} }
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++)
sum_items(*i, item, compute_subtotals); sum_items(*i, constraints, item);
} }
item_t * walk_items(const item_t * top, item_t * walk_items(const item_t * top, const account_t * account,
const account_t * account, const constraints_t& constraints)
const constraints_t& constraints,
const bool compute_subtotals)
{ {
item_t * item = new item_t; item_t * item = new item_t;
item->account = account; item->account = account;
sum_items(top, item, compute_subtotals); sum_items(top, constraints, item);
for (accounts_map::const_iterator i = account->accounts.begin(); for (accounts_map::const_iterator i = account->accounts.begin();
i != account->accounts.end(); i != account->accounts.end();
i++) { i++) {
item_t * subitem = walk_items(top, (*i).second, constraints, item_t * subitem = walk_items(top, (*i).second, constraints);
compute_subtotals);
subitem->parent = item; subitem->parent = item;
if (compute_subtotals) if (constraints.show_subtotals)
item->total += subitem->total; item->total += subitem->total;
if (compute_subtotals ? subitem->total : subitem->value) if (constraints.show_subtotals ? subitem->total : subitem->value)
item->subitems.push_back(subitem); item->subitems.push_back(subitem);
} }

15
item.h
View file

@ -15,6 +15,8 @@ typedef std::deque<item_t *> items_deque;
struct item_t struct item_t
{ {
struct item_t * parent; struct item_t * parent;
items_deque subitems;
unsigned int index; unsigned int index;
std::time_t date; std::time_t date;
std::string payee; std::string payee;
@ -22,8 +24,6 @@ struct item_t
balance_pair_t value; balance_pair_t value;
balance_pair_t total; balance_pair_t total;
items_deque subitems;
item_t() : parent(NULL), index(0), date(-1), account(NULL) {} item_t() : parent(NULL), index(0), date(-1), account(NULL) {}
~item_t() { ~item_t() {
@ -38,14 +38,11 @@ struct item_t
class constraints_t; class constraints_t;
item_t * walk_accounts(const account_t * account, item_t * walk_accounts(const account_t * account,
const constraints_t& constraints, const constraints_t& constraints);
const bool compute_subtotals);
item_t * walk_items(const item_t * top, item_t * walk_items(const item_t * top, const account_t * account,
const account_t * account, const constraints_t& constraints);
const constraints_t& constraints,
const bool compute_subtotals);
item_t * walk_entries(entries_list::const_iterator begin, item_t * walk_entries(entries_list::const_iterator begin,
entries_list::const_iterator end, entries_list::const_iterator end,

17
main.cc
View file

@ -504,10 +504,10 @@ 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 = NULL; ledger::ledger_t * book = NULL;
ledger::constraints_t constraints; ledger::constraints_t constraints;
ledger::format_t format; ledger::format_t format;
std::string sort_order; std::string sort_order;
std::string value_style = "a"; std::string value_style = "a";
@ -826,8 +826,7 @@ int main(int argc, char * argv[])
else if (command == "equity") { else if (command == "equity") {
#if 0 #if 0
ledger::item_t * top ledger::item_t * top
= ledger::walk_accounts(book->master, constraints, = ledger::walk_accounts(book->master, constraints);
constraints.show_subtotals);
ledger::entry_report(std::cout, top, constraints, format); ledger::entry_report(std::cout, top, constraints, format);
@ -843,8 +842,7 @@ int main(int argc, char * argv[])
format.format_string = ledger::bal_fmt; 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(book->master, constraints)) {
constraints.show_subtotals)) {
ledger::balance_report(std::cout, top, constraints, format); ledger::balance_report(std::cout, top, constraints, format);
#ifdef DEBUG #ifdef DEBUG
delete top; delete top;
@ -859,8 +857,7 @@ int main(int argc, char * argv[])
= ledger::walk_entries(book->entries.begin(), = ledger::walk_entries(book->entries.begin(),
book->entries.end(), constraints)) book->entries.end(), constraints))
if (ledger::item_t * top if (ledger::item_t * top
= ledger::walk_items(list, book->master, constraints, = ledger::walk_items(list, book->master, constraints)) {
constraints.show_subtotals)) {
ledger::balance_report(std::cout, top, constraints, format); ledger::balance_report(std::cout, top, constraints, format);
#ifdef DEBUG #ifdef DEBUG
delete top; delete top;

View file

@ -1,6 +1,6 @@
#include "ledger.h"
#include "constraint.h"
#include "textual.h" #include "textual.h"
#include "constraint.h"
#include "error.h"
#include <vector> #include <vector>
#include <fstream> #include <fstream>
@ -14,7 +14,7 @@
namespace ledger { namespace ledger {
#if 0 #if 0
static const std::string entry1_fmt = "%?10d %p"; static const std::string entry1_fmt = "%10d %p";
static const std::string entryn_fmt = " %-30a %15t"; static const std::string entryn_fmt = " %-30a %15t";
#endif #endif
@ -360,13 +360,11 @@ void parse_automated_transactions(std::istream& in, ledger_t * ledger,
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, ledger, account, NULL)) {
if (! xact->amount) { if (! xact->amount)
std::cerr << "Error in " << path << ", line " << (linenum - 1) throw parse_error(path, linenum,
<< ": All automated transactions must have a value." "All automated transactions must have a value");
<< std::endl; else
} else {
xacts.push_back(xact); xacts.push_back(xact);
}
} }
} }
@ -461,11 +459,8 @@ entry_t * parse_entry(std::istream& in, ledger_t * ledger,
char * next = next_element(line); char * next = next_element(line);
if (! quick_parse_date(line, &curr->date)) { if (! quick_parse_date(line, &curr->date))
std::cerr << "Error in " << path << ", line " << (linenum - 1) throw parse_error(path, linenum, "Failed to parse date");
<< ": Failed to parse date: " << line << std::endl;
return NULL;
}
// Parse the optional cleared flag: * // Parse the optional cleared flag: *
@ -532,241 +527,241 @@ unsigned int parse_textual_ledger(std::istream& in, ledger_t *& ledger,
linenum = 1; linenum = 1;
while (! in.eof()) { while (! in.eof()) {
switch (in.peek()) { try {
case -1: // end of file switch (in.peek()) {
goto done; case -1: // end of file
goto done;
case ' ': case ' ':
case '\t': case '\t':
if (peek_next_nonws(in) != '\n') { if (peek_next_nonws(in) != '\n') {
std::cerr << "Error in " << path << ", line " << (linenum - 1) in.getline(line, MAX_LINE);
<< ": Ignoring entry beginning with whitespace." linenum++;
<< std::endl; throw parse_error(path, linenum,
in.getline(line, MAX_LINE); "Ignoring entry beginning with whitespace");
}
// fall through...
case '\n':
linenum++; linenum++;
case '\r': // skip blank lines
in.get(c);
break; break;
}
// fall through...
case '\n':
linenum++;
case '\r': // skip blank lines
in.get(c);
break;
#ifdef TIMELOG_SUPPORT #ifdef TIMELOG_SUPPORT
case 'i': case 'i':
case 'I': { case 'I': {
std::string date, time;
in >> c;
in >> date;
in >> time;
date += " ";
date += time;
in.getline(line, MAX_LINE);
linenum++;
char * p = skip_ws(line);
char * n = next_element(p, true);
last_desc = n ? n : "";
static struct std::tm when;
if (strptime(date.c_str(), "%Y/%m/%d %H:%M:%S", &when)) {
time_in = std::mktime(&when);
last_account = account_stack.front()->find_account(p);
} else {
std::cerr << "Error in " << path << ", line " << (linenum - 1)
<< ": Cannot parse timelog entry date." << std::endl;
last_account = NULL;
}
break;
}
case 'o':
case 'O':
if (last_account) {
std::string date, time; std::string date, time;
in >> c; in >> c;
in >> date; in >> date;
in >> time; in >> time;
in.getline(line, MAX_LINE);
linenum++;
date += " "; date += " ";
date += time; date += time;
in.getline(line, MAX_LINE);
linenum++;
char * p = skip_ws(line);
char * n = next_element(p, true);
last_desc = n ? n : "";
static struct std::tm when; static struct std::tm when;
if (strptime(date.c_str(), "%Y/%m/%d %H:%M:%S", &when)) { if (strptime(date.c_str(), "%Y/%m/%d %H:%M:%S", &when)) {
entry_t * curr = new entry_t; time_in = std::mktime(&when);
curr->date = std::mktime(&when); last_account = account_stack.front()->find_account(p);
curr->state = entry_t::CLEARED;
curr->code = "";
curr->payee = last_desc;
double diff = std::difftime(curr->date, time_in) / 60.0 / 60.0;
char buf[32];
std::sprintf(buf, "%fh", diff);
amount_t amt;
amt.parse(buf, ledger);
time_commodity = amt.commodity;
transaction_t * xact = new transaction_t(curr, last_account, amt, amt,
TRANSACTION_VIRTUAL);
curr->add_transaction(xact);
if (! finalize_entry(curr) || ! ledger->add_entry(curr))
assert(0);
count++;
} else { } else {
std::cerr << "Error in " << path << ", line " << (linenum - 1) last_account = NULL;
<< ": Cannot parse timelog entry date." << std::endl; throw parse_error(path, linenum, "Cannot parse timelog entry date");
} }
break;
last_account = NULL;
} else {
in.getline(line, MAX_LINE);
linenum++;
} }
break;
case 'o':
case 'O':
if (last_account) {
std::string date, time;
in >> c;
in >> date;
in >> time;
in.getline(line, MAX_LINE);
linenum++;
date += " ";
date += time;
static struct std::tm when;
if (strptime(date.c_str(), "%Y/%m/%d %H:%M:%S", &when)) {
entry_t * curr = new entry_t;
curr->date = std::mktime(&when);
curr->state = entry_t::CLEARED;
curr->code = "";
curr->payee = last_desc;
double diff = std::difftime(curr->date, time_in) / 60.0 / 60.0;
char buf[32];
std::sprintf(buf, "%fh", diff);
amount_t amt;
amt.parse(buf, ledger);
time_commodity = amt.commodity;
transaction_t * xact = new transaction_t(curr, last_account, amt, amt,
TRANSACTION_VIRTUAL);
curr->add_transaction(xact);
if (! finalize_entry(curr) || ! ledger->add_entry(curr))
assert(0);
count++;
} else {
throw parse_error(path, linenum, "Cannot parse timelog entry date");
}
last_account = NULL;
} else {
in.getline(line, MAX_LINE);
linenum++;
}
break;
#endif // TIMELOG_SUPPORT #endif // TIMELOG_SUPPORT
case 'P': { // a pricing entry case 'P': { // a pricing entry
in >> c; in >> c;
std::time_t date; std::time_t date;
std::string symbol; std::string symbol;
in >> line; // the date in >> line; // the date
if (! quick_parse_date(line, &date)) { if (! quick_parse_date(line, &date))
std::cerr << "Error in " << path << ", line " << (linenum - 1) throw parse_error(path, linenum, "Failed to parse date");
<< ": Failed to parse date: " << line << std::endl;
int hour, min, sec;
in >> hour; // the time
in >> c;
in >> min;
in >> c;
in >> sec;
date = std::time_t(((unsigned long) date) +
hour * 3600 + min * 60 + sec);
amount_t price;
parse_commodity(in, symbol);
in >> line; // the price
price.parse(line, ledger);
commodity_t * commodity = ledger->find_commodity(symbol, true);
commodity->add_price(date, price);
break; break;
} }
int hour, min, sec; case 'N': { // don't download prices
std::string symbol;
in >> hour; // the time in >> c;
in >> c; parse_commodity(in, symbol);
in >> min;
in >> c;
in >> sec;
date = std::time_t(((unsigned long) date) + commodity_t * commodity = ledger->find_commodity(line, true);
hour * 3600 + min * 60 + sec); commodity->flags |= (COMMODITY_STYLE_CONSULTED |
COMMODITY_STYLE_NOMARKET);
break;
}
amount_t price; case 'C': { // a flat conversion
in >> c;
parse_commodity(in, symbol); std::string symbol;
in >> line; // the price amount_t price;
price.parse(line, ledger);
commodity_t * commodity = ledger->find_commodity(symbol, true); parse_commodity(in, symbol);
commodity->add_price(date, price); in >> line; // the price
break; price.parse(line, ledger);
}
case 'N': { // don't download prices commodity_t * commodity = ledger->find_commodity(symbol, true);
std::string symbol; commodity->set_conversion(price);
break;
}
in >> c; case 'Y': // set the current year
parse_commodity(in, symbol); in >> c;
in >> now_tm->tm_year;
commodity_t * commodity = ledger->find_commodity(line, true); now_tm->tm_year -= 1900;
commodity->flags |= (COMMODITY_STYLE_CONSULTED | break;
COMMODITY_STYLE_NOMARKET);
break;
}
case 'C': { // a flat conversion
in >> c;
std::string symbol;
amount_t price;
parse_commodity(in, symbol);
in >> line; // the price
price.parse(line, ledger);
commodity_t * commodity = ledger->find_commodity(symbol, true);
commodity->set_conversion(price);
break;
}
case 'Y': // set the current year
in >> c;
in >> now_tm->tm_year;
now_tm->tm_year -= 1900;
break;
#ifdef TIMELOG_SUPPORT #ifdef TIMELOG_SUPPORT
case 'h': case 'h':
case 'b': case 'b':
#endif #endif
case ';': // a comment line case ';': // a comment line
in.getline(line, MAX_LINE); in.getline(line, MAX_LINE);
linenum++; linenum++;
break;
case '=': // automated transactions
parse_automated_transactions(in, ledger, account_stack.front(),
auto_xacts);
break;
case '@': { // account specific
in >> c;
if (in.peek() == '@') {
in.get(c);
account_stack.pop_front();
break; break;
}
in.getline(line, MAX_LINE); case '=': // automated transactions
linenum++; parse_automated_transactions(in, ledger, account_stack.front(),
auto_xacts);
break;
account_t * acct = account_stack.front()->find_account(skip_ws(line)); case '@': { // account specific
account_stack.push_front(acct); in >> c;
break; if (in.peek() == '@') {
} in.get(c);
account_stack.pop_front();
break;
}
case '!': // directive
in >> line;
if (std::string(line) == "!include") {
in.getline(line, MAX_LINE); in.getline(line, MAX_LINE);
linenum++; linenum++;
char * path = skip_ws(line); account_t * acct = account_stack.front()->find_account(skip_ws(line));
std::ifstream stream(path); account_stack.push_front(acct);
break;
ledger->sources.push_back(path);
unsigned int curr_linenum = linenum;
count += parse_textual_ledger(stream, ledger, account_stack.front());
linenum = curr_linenum;
} }
break;
default: { case '!': // directive
unsigned int first_line = linenum; in >> line;
if (entry_t * entry = parse_entry(in, ledger, account_stack.front())) { if (std::string(line) == "!include") {
if (! auto_xacts.automated_transactions.empty()) in.getline(line, MAX_LINE);
auto_xacts.extend_entry(entry); linenum++;
if (ledger->add_entry(entry)) char * p = skip_ws(line);
count++; std::ifstream stream(p);
else
std::cerr << "Error in " << path << ", line " << first_line ledger->sources.push_back(p);
<< ": Entry does not balance." << std::endl;
} else { unsigned int curr_linenum = linenum;
std::cerr << "Error in " << path << ", line " << first_line std::string curr_path = path;
<< ": Failed to parse entry." << std::endl;
count += parse_textual_ledger(stream, ledger, account_stack.front());
linenum = curr_linenum;
path = curr_path;
}
break;
default: {
unsigned int first_line = linenum;
if (entry_t * entry = parse_entry(in, ledger, account_stack.front())) {
if (! auto_xacts.automated_transactions.empty())
auto_xacts.extend_entry(entry);
if (ledger->add_entry(entry))
count++;
else
throw parse_error(path, first_line, "Entry does not balance");
} else {
throw parse_error(path, first_line, "Failed to parse entry");
}
break;
}
} }
break;
} }
catch (const parse_error& err) {
std::cerr << err.what() << std::endl;
} }
} }