diff options
-rw-r--r-- | constraint.cc | 4 | ||||
-rw-r--r-- | item.cc | 37 | ||||
-rw-r--r-- | item.h | 15 | ||||
-rw-r--r-- | main.cc | 17 | ||||
-rw-r--r-- | textual.cc | 385 |
5 files changed, 223 insertions, 235 deletions
diff --git a/constraint.cc b/constraint.cc index 0af49502..4720e62b 100644 --- a/constraint.cc +++ b/constraint.cc @@ -200,6 +200,10 @@ bool constraints_t::operator ()(const item_t * item) const return false; #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()) { bool match = false; @@ -8,8 +8,7 @@ namespace ledger { // subaccounts, empty balanced or no item_t * walk_accounts(const account_t * account, - const constraints_t& constraints, - const bool compute_subtotals) + const constraints_t& constraints) { item_t * item = new item_t; item->account = account; @@ -21,64 +20,60 @@ item_t * walk_accounts(const account_t * account, i != account->transactions.end(); i++) { item->value += *(*i); - if (compute_subtotals) + if (constraints.show_subtotals) item->total += *(*i); } for (accounts_map::const_iterator i = account->accounts.begin(); i != account->accounts.end(); i++) { - item_t * subitem = walk_accounts((*i).second, constraints, - compute_subtotals); + item_t * subitem = walk_accounts((*i).second, constraints); subitem->parent = item; - if (compute_subtotals) + if (constraints.show_subtotals) item->total += subitem->total; - if (compute_subtotals ? subitem->total : subitem->value) + if (constraints.show_subtotals ? subitem->total : subitem->value) item->subitems.push_back(subitem); } return item; } -static inline void sum_items(const item_t * top, - item_t * item, - const bool compute_subtotals) +static inline void sum_items(const item_t * top, + const constraints_t& constraints, + item_t * item) { if (top->account == item->account) { item->value += top->value; - if (compute_subtotals) + if (constraints.show_subtotals) item->total += top->value; } for (items_deque::const_iterator i = top->subitems.begin(); i != top->subitems.end(); i++) - sum_items(*i, item, compute_subtotals); + sum_items(*i, constraints, item); } -item_t * walk_items(const item_t * top, - const account_t * account, - const constraints_t& constraints, - const bool compute_subtotals) +item_t * walk_items(const item_t * top, const account_t * account, + const constraints_t& constraints) { item_t * item = new item_t; item->account = account; - sum_items(top, item, compute_subtotals); + sum_items(top, constraints, item); for (accounts_map::const_iterator i = account->accounts.begin(); i != account->accounts.end(); i++) { - item_t * subitem = walk_items(top, (*i).second, constraints, - compute_subtotals); + item_t * subitem = walk_items(top, (*i).second, constraints); subitem->parent = item; - if (compute_subtotals) + if (constraints.show_subtotals) item->total += subitem->total; - if (compute_subtotals ? subitem->total : subitem->value) + if (constraints.show_subtotals ? subitem->total : subitem->value) item->subitems.push_back(subitem); } @@ -15,6 +15,8 @@ typedef std::deque<item_t *> items_deque; struct item_t { struct item_t * parent; + items_deque subitems; + unsigned int index; std::time_t date; std::string payee; @@ -22,8 +24,6 @@ struct item_t balance_pair_t value; balance_pair_t total; - items_deque subitems; - item_t() : parent(NULL), index(0), date(-1), account(NULL) {} ~item_t() { @@ -38,14 +38,11 @@ struct item_t class constraints_t; -item_t * walk_accounts(const account_t * account, - const constraints_t& constraints, - const bool compute_subtotals); +item_t * walk_accounts(const account_t * account, + const constraints_t& constraints); -item_t * walk_items(const item_t * top, - const account_t * account, - const constraints_t& constraints, - const bool compute_subtotals); +item_t * walk_items(const item_t * top, const account_t * account, + const constraints_t& constraints); item_t * walk_entries(entries_list::const_iterator begin, entries_list::const_iterator end, @@ -504,10 +504,10 @@ static void show_help(std::ostream& out) int main(int argc, char * argv[]) { - std::list<std::string> files; - ledger::ledger_t * book = NULL; - ledger::constraints_t constraints; - ledger::format_t format; + std::list<std::string> files; + ledger::ledger_t * book = NULL; + ledger::constraints_t constraints; + ledger::format_t format; std::string sort_order; std::string value_style = "a"; @@ -826,8 +826,7 @@ int main(int argc, char * argv[]) else if (command == "equity") { #if 0 ledger::item_t * top - = ledger::walk_accounts(book->master, constraints, - constraints.show_subtotals); + = ledger::walk_accounts(book->master, constraints); ledger::entry_report(std::cout, top, constraints, format); @@ -843,8 +842,7 @@ int main(int argc, char * argv[]) format.format_string = ledger::bal_fmt; if (ledger::item_t * top - = ledger::walk_accounts(book->master, constraints, - constraints.show_subtotals)) { + = ledger::walk_accounts(book->master, constraints)) { ledger::balance_report(std::cout, top, constraints, format); #ifdef DEBUG delete top; @@ -859,8 +857,7 @@ int main(int argc, char * argv[]) = ledger::walk_entries(book->entries.begin(), book->entries.end(), constraints)) if (ledger::item_t * top - = ledger::walk_items(list, book->master, constraints, - constraints.show_subtotals)) { + = ledger::walk_items(list, book->master, constraints)) { ledger::balance_report(std::cout, top, constraints, format); #ifdef DEBUG delete top; @@ -1,6 +1,6 @@ -#include "ledger.h" -#include "constraint.h" #include "textual.h" +#include "constraint.h" +#include "error.h" #include <vector> #include <fstream> @@ -14,7 +14,7 @@ namespace ledger { #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"; #endif @@ -360,13 +360,11 @@ void parse_automated_transactions(std::istream& in, ledger_t * ledger, while (! in.eof() && (in.peek() == ' ' || in.peek() == '\t')) { if (transaction_t * xact = parse_transaction(in, ledger, account, NULL)) { - if (! xact->amount) { - std::cerr << "Error in " << path << ", line " << (linenum - 1) - << ": All automated transactions must have a value." - << std::endl; - } else { + if (! xact->amount) + throw parse_error(path, linenum, + "All automated transactions must have a value"); + else xacts.push_back(xact); - } } } @@ -461,11 +459,8 @@ entry_t * parse_entry(std::istream& in, ledger_t * ledger, char * next = next_element(line); - if (! quick_parse_date(line, &curr->date)) { - std::cerr << "Error in " << path << ", line " << (linenum - 1) - << ": Failed to parse date: " << line << std::endl; - return NULL; - } + if (! quick_parse_date(line, &curr->date)) + throw parse_error(path, linenum, "Failed to parse date"); // Parse the optional cleared flag: * @@ -532,241 +527,241 @@ unsigned int parse_textual_ledger(std::istream& in, ledger_t *& ledger, linenum = 1; while (! in.eof()) { - switch (in.peek()) { - case -1: // end of file - goto done; - - case ' ': - case '\t': - if (peek_next_nonws(in) != '\n') { - std::cerr << "Error in " << path << ", line " << (linenum - 1) - << ": Ignoring entry beginning with whitespace." - << std::endl; - in.getline(line, MAX_LINE); + try { + switch (in.peek()) { + case -1: // end of file + goto done; + + case ' ': + case '\t': + if (peek_next_nonws(in) != '\n') { + in.getline(line, MAX_LINE); + linenum++; + throw parse_error(path, linenum, + "Ignoring entry beginning with whitespace"); + } + // fall through... + + case '\n': linenum++; + case '\r': // skip blank lines + in.get(c); break; - } - // fall through... - - case '\n': - linenum++; - case '\r': // skip blank lines - in.get(c); - break; #ifdef TIMELOG_SUPPORT - 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) { + case 'i': + case 'I': { std::string date, time; in >> c; in >> date; in >> time; + date += " "; + date += time; in.getline(line, MAX_LINE); linenum++; - date += " "; - date += time; + 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)) { - 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++; + 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; + throw parse_error(path, linenum, "Cannot parse timelog entry date"); } - - last_account = NULL; - } else { - in.getline(line, MAX_LINE); - linenum++; + break; } - 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 - case 'P': { // a pricing entry - in >> c; + case 'P': { // a pricing entry + in >> c; - std::time_t date; - std::string symbol; + std::time_t date; + std::string symbol; - in >> line; // the date - if (! quick_parse_date(line, &date)) { - std::cerr << "Error in " << path << ", line " << (linenum - 1) - << ": Failed to parse date: " << line << std::endl; - break; - } + in >> line; // the date + if (! quick_parse_date(line, &date)) + throw parse_error(path, linenum, "Failed to parse date"); - int hour, min, sec; + int hour, min, sec; - in >> hour; // the time - in >> c; - in >> min; - in >> c; - in >> 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); + date = std::time_t(((unsigned long) date) + + hour * 3600 + min * 60 + sec); - amount_t price; + amount_t price; - parse_commodity(in, symbol); - in >> line; // the price - price.parse(line, ledger); + 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; - } + commodity_t * commodity = ledger->find_commodity(symbol, true); + commodity->add_price(date, price); + break; + } - case 'N': { // don't download prices - std::string symbol; + case 'N': { // don't download prices + std::string symbol; - in >> c; - parse_commodity(in, symbol); + in >> c; + parse_commodity(in, symbol); - commodity_t * commodity = ledger->find_commodity(line, true); - commodity->flags |= (COMMODITY_STYLE_CONSULTED | - COMMODITY_STYLE_NOMARKET); - break; - } + commodity_t * commodity = ledger->find_commodity(line, true); + commodity->flags |= (COMMODITY_STYLE_CONSULTED | + COMMODITY_STYLE_NOMARKET); + break; + } - case 'C': { // a flat conversion - in >> c; + case 'C': { // a flat conversion + in >> c; - std::string symbol; - amount_t price; + std::string symbol; + amount_t price; - parse_commodity(in, symbol); - in >> line; // the price - price.parse(line, ledger); + 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; - } + 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; + case 'Y': // set the current year + in >> c; + in >> now_tm->tm_year; + now_tm->tm_year -= 1900; + break; #ifdef TIMELOG_SUPPORT - case 'h': - case 'b': + case 'h': + case 'b': #endif - case ';': // a comment line - in.getline(line, MAX_LINE); - linenum++; - break; + case ';': // a comment line + in.getline(line, MAX_LINE); + linenum++; + break; - case '=': // automated transactions - parse_automated_transactions(in, ledger, account_stack.front(), - auto_xacts); - 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(); + case '@': { // account specific + in >> c; + if (in.peek() == '@') { + in.get(c); + account_stack.pop_front(); + break; + } + + in.getline(line, MAX_LINE); + linenum++; + + account_t * acct = account_stack.front()->find_account(skip_ws(line)); + account_stack.push_front(acct); break; } - in.getline(line, MAX_LINE); - linenum++; + case '!': // directive + in >> line; + if (std::string(line) == "!include") { + in.getline(line, MAX_LINE); + linenum++; - account_t * acct = account_stack.front()->find_account(skip_ws(line)); - account_stack.push_front(acct); - break; - } + char * p = skip_ws(line); + std::ifstream stream(p); - case '!': // directive - in >> line; - if (std::string(line) == "!include") { - in.getline(line, MAX_LINE); - linenum++; + ledger->sources.push_back(p); - char * path = skip_ws(line); - std::ifstream stream(path); + unsigned int curr_linenum = linenum; + std::string curr_path = path; - ledger->sources.push_back(path); + count += parse_textual_ledger(stream, ledger, account_stack.front()); - unsigned int curr_linenum = linenum; - count += parse_textual_ledger(stream, ledger, account_stack.front()); - linenum = curr_linenum; - } - break; + 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); + 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 - std::cerr << "Error in " << path << ", line " << first_line - << ": Entry does not balance." << std::endl; - } else { - std::cerr << "Error in " << path << ", line " << first_line - << ": Failed to parse entry." << std::endl; + 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; } } |