diff options
-rw-r--r-- | amount.cc | 20 | ||||
-rw-r--r-- | config.cc | 1 | ||||
-rw-r--r-- | config.h | 8 | ||||
-rw-r--r-- | main.cc | 36 | ||||
-rw-r--r-- | textual.cc | 49 |
5 files changed, 85 insertions, 29 deletions
@@ -698,8 +698,6 @@ void amount_t::parse(std::istream& in) std::string quant; unsigned int flags = COMMODITY_STYLE_DEFAULTS;; - _init(); - char c = peek_next_nonws(in); if (std::isdigit(c) || c == '.' || c == '-') { parse_quantity(in, quant); @@ -722,6 +720,11 @@ void amount_t::parse(std::istream& in) parse_quantity(in, quant); } + if (quant.empty()) + throw amount_error("No quantity specified for amount"); + + _init(); + std::string::size_type last_comma = quant.rfind(','); std::string::size_type last_period = quant.rfind('.'); @@ -745,7 +748,9 @@ void amount_t::parse(std::istream& in) quantity->prec = 0; } - // Create the commodity if has not already been seen. + // Create the commodity if has not already been seen, and update the + // precision if something greater was used for the quantity. + commodity_ = commodity_t::find_commodity(symbol, true); commodity_->flags |= flags; if (quantity->prec > commodity_->precision) @@ -879,16 +884,15 @@ void amount_t::write_quantity(std::ostream& out) const mpz_export(buf, &size, 1, sizeof(short), 0, 0, MPZ(quantity)); unsigned short len = size * sizeof(short); out.write((char *)&len, sizeof(len)); - if (len) { assert(len < 4096); out.write(buf, len); + } - byte = mpz_sgn(MPZ(quantity)) < 0 ? 1 : 0; - out.write(&byte, sizeof(byte)); + byte = mpz_sgn(MPZ(quantity)) < 0 ? 1 : 0; + out.write(&byte, sizeof(byte)); - out.write((char *)&quantity->prec, sizeof(quantity->prec)); - } + out.write((char *)&quantity->prec, sizeof(quantity->prec)); } else { assert(quantity->ref > 1); @@ -29,6 +29,7 @@ config_t::config_t() plot_total_format = "%D %T\n"; print_format = "\n%D %X%C%P\n %-34N %12o\n%/ %-34N %12o\n"; equity_format = "\n%D %X%C%P\n%/ %-34N %12t\n"; + prices_format = "%D %-10N %12t %12T\n"; show_collapsed = false; show_subtotal = false; @@ -14,13 +14,6 @@ namespace ledger { -extern std::string bal_fmt; -extern std::string reg_fmt; -extern std::string plot_value_fmt; -extern std::string plot_total_fmt; -extern std::string print_fmt; -extern std::string equity_fmt; - struct config_t { // These options can all be set used text fields. @@ -42,6 +35,7 @@ struct config_t std::string plot_total_format; std::string print_format; std::string equity_format; + std::string prices_format; std::string date_format; std::string sort_string; std::string amount_expr; @@ -137,6 +137,36 @@ chain_formatters(const std::string& command, return formatter; } +void walk_commodities(commodities_map& commodities, + item_handler<transaction_t>& handler) +{ + std::list<transaction_t> xact_temps; + std::list<entry_t> entry_temps; + std::list<account_t> acct_temps; + + for (commodities_map::iterator i = commodities.begin(); + i != commodities.end(); + i++) { + if ((*i).second->flags & COMMODITY_STYLE_NOMARKET) + continue; + + entry_temps.push_back(entry_t()); + acct_temps.push_back(account_t(NULL, (*i).second->symbol)); + + for (history_map::iterator j = (*i).second->history.begin(); + j != (*i).second->history.end(); + j++) { + entry_temps.back().date = (*j).first; + + xact_temps.push_back(transaction_t(&acct_temps.back())); + xact_temps.back().entry = &entry_temps.back(); + xact_temps.back().amount = (*j).second; + + handler(xact_temps.back()); + } + } +} + int parse_and_report(int argc, char * argv[], char * envp[]) { std::auto_ptr<journal_t> journal(new journal_t); @@ -186,6 +216,8 @@ int parse_and_report(int argc, char * argv[], char * envp[]) command = "e"; else if (command == "equity") command = "E"; + else if (command == "prices") + command = "P"; else throw error(std::string("Unrecognized command '") + command + "'"); @@ -240,6 +272,8 @@ int parse_and_report(int argc, char * argv[], char * envp[]) format = &config.register_format; else if (command == "E") format = &config.equity_format; + else if (command == "P") + format = &config.prices_format; else format = &config.print_format; @@ -259,6 +293,8 @@ int parse_and_report(int argc, char * argv[], char * envp[]) if (command == "e") walk_transactions(new_entry->transactions, *formatter); + else if (command == "P") + walk_commodities(commodity_t::commodities, *formatter); else walk_entries(journal->entries, *formatter); @@ -69,26 +69,37 @@ transaction_t * parse_transaction_text(char * line, account_t * account, char * p = skip_ws(line); if (char * cost_str = next_element(p, true)) { + cost_str = skip_ws(cost_str); + bool has_amount = *cost_str; + if (char * note_str = std::strchr(cost_str, ';')) { + if (cost_str == note_str) + has_amount = false; *note_str++ = '\0'; xact->note = skip_ws(note_str); } - char * price_str = std::strchr(cost_str, '@'); - bool per_unit = true; - if (price_str) { - *price_str++ = '\0'; - if (*price_str == '@') { - per_unit = false; - price_str++; + if (has_amount) { + bool per_unit = true; + char * price_str = std::strchr(cost_str, '@'); + if (price_str) { + if (price_str == cost_str) + throw parse_error(path, linenum, "Cost specified without amount"); + + *price_str++ = '\0'; + if (*price_str == '@') { + per_unit = false; + price_str++; + } + xact->cost = new amount_t; + xact->cost->parse(price_str); } - xact->cost = new amount_t; - xact->cost->parse(price_str); - } - xact->amount.parse(cost_str); - if (price_str && per_unit) - *xact->cost *= xact->amount; + xact->amount.parse(cost_str); + + if (price_str && per_unit) + *xact->cost *= xact->amount; + } } if (*p == '[' || *p == '(') { @@ -252,7 +263,7 @@ unsigned int textual_parser_t::parse(std::istream& in, if (peek_next_nonws(in) != '\n') { in.getline(line, MAX_LINE); linenum++; - throw parse_error(path, linenum, "Line begins with whitespace"); + throw parse_error(path, linenum - 1, "Line begins with whitespace"); } // fall through... @@ -490,6 +501,16 @@ unsigned int textual_parser_t::parse(std::istream& in, std::cerr << "Error: " << err.what() << std::endl; errors++; } + catch (const amount_error& err) { + std::cerr << "Error: " << path << ", line " << (linenum - 1) << ": " + << err.what() << std::endl;; + errors++; + } + catch (const error& err) { + std::cerr << "Error: " << path << ", line " << (linenum - 1) << ": " + << err.what() << std::endl;; + errors++; + } } done: |