summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--amount.cc20
-rw-r--r--config.cc1
-rw-r--r--config.h8
-rw-r--r--main.cc36
-rw-r--r--textual.cc49
5 files changed, 85 insertions, 29 deletions
diff --git a/amount.cc b/amount.cc
index 65f99e90..a01ac9f9 100644
--- a/amount.cc
+++ b/amount.cc
@@ -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);
diff --git a/config.cc b/config.cc
index 85c90427..dc789602 100644
--- a/config.cc
+++ b/config.cc
@@ -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;
diff --git a/config.h b/config.h
index 5c7bba2e..53884c36 100644
--- a/config.h
+++ b/config.h
@@ -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;
diff --git a/main.cc b/main.cc
index f1dbeff4..cc26d433 100644
--- a/main.cc
+++ b/main.cc
@@ -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);
diff --git a/textual.cc b/textual.cc
index 1916860a..aea860e2 100644
--- a/textual.cc
+++ b/textual.cc
@@ -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: