Added much better error location.
This commit is contained in:
parent
b737cd8e6d
commit
e32d9e64a7
37 changed files with 1108 additions and 447 deletions
|
|
@ -20,6 +20,7 @@ libledger_la_SOURCES = \
|
|||
config.cc \
|
||||
derive.cc \
|
||||
emacs.cc \
|
||||
error.cc \
|
||||
format.cc \
|
||||
journal.cc \
|
||||
mask.cc \
|
||||
|
|
|
|||
49
amount.cc
49
amount.cc
|
|
@ -378,7 +378,7 @@ amount_t& amount_t::operator+=(const amount_t& amt)
|
|||
_dup();
|
||||
|
||||
if (commodity_ != amt.commodity_)
|
||||
throw amount_error("Adding amounts with different commodities");
|
||||
throw new amount_error("Adding amounts with different commodities");
|
||||
|
||||
if (quantity->prec == amt.quantity->prec) {
|
||||
mpz_add(MPZ(quantity), MPZ(quantity), MPZ(amt.quantity));
|
||||
|
|
@ -411,7 +411,7 @@ amount_t& amount_t::operator-=(const amount_t& amt)
|
|||
_dup();
|
||||
|
||||
if (commodity_ != amt.commodity_)
|
||||
throw amount_error("Subtracting amounts with different commodities");
|
||||
throw new amount_error("Subtracting amounts with different commodities");
|
||||
|
||||
if (quantity->prec == amt.quantity->prec) {
|
||||
mpz_sub(MPZ(quantity), MPZ(quantity), MPZ(amt.quantity));
|
||||
|
|
@ -453,7 +453,7 @@ amount_t& amount_t::operator*=(const amount_t& amt)
|
|||
amount_t& amount_t::operator/=(const amount_t& amt)
|
||||
{
|
||||
if (! amt.quantity || ! amt)
|
||||
throw amount_error("Divide by zero");
|
||||
throw new amount_error("Divide by zero");
|
||||
else if (! quantity)
|
||||
return *this;
|
||||
|
||||
|
|
@ -919,7 +919,7 @@ void parse_commodity(std::istream& in, std::string& symbol)
|
|||
if (c == '"')
|
||||
in.get(c);
|
||||
else
|
||||
throw amount_error("Quoted commodity symbol lacks closing quote");
|
||||
throw new amount_error("Quoted commodity symbol lacks closing quote");
|
||||
} else {
|
||||
READ_INTO(in, buf, 255, c, ! std::isspace(c) && ! std::isdigit(c) &&
|
||||
c != '-' && c != '.');
|
||||
|
|
@ -939,14 +939,14 @@ void parse_annotations(std::istream& in, const std::string& symbol,
|
|||
char c = peek_next_nonws(in);
|
||||
if (c == '{') {
|
||||
if (! price.empty())
|
||||
throw amount_error("Commodity specifies more than one price");
|
||||
throw new amount_error("Commodity specifies more than one price");
|
||||
|
||||
in.get(c);
|
||||
READ_INTO(in, buf, 255, c, c != '}');
|
||||
if (c == '}')
|
||||
in.get(c);
|
||||
else
|
||||
throw amount_error("Commodity price lacks closing brace");
|
||||
throw new amount_error("Commodity price lacks closing brace");
|
||||
price = buf;
|
||||
if (! added_name) {
|
||||
added_name = true;
|
||||
|
|
@ -962,14 +962,14 @@ void parse_annotations(std::istream& in, const std::string& symbol,
|
|||
}
|
||||
else if (c == '[') {
|
||||
if (! date.empty())
|
||||
throw amount_error("Commodity specifies more than one date");
|
||||
throw new amount_error("Commodity specifies more than one date");
|
||||
|
||||
in.get(c);
|
||||
READ_INTO(in, buf, 255, c, c != ']');
|
||||
if (c == ']')
|
||||
in.get(c);
|
||||
else
|
||||
throw amount_error("Commodity date lacks closing bracket");
|
||||
throw new amount_error("Commodity date lacks closing bracket");
|
||||
date = buf;
|
||||
if (! added_name) {
|
||||
added_name = true;
|
||||
|
|
@ -985,14 +985,14 @@ void parse_annotations(std::istream& in, const std::string& symbol,
|
|||
}
|
||||
else if (c == '(') {
|
||||
if (! tag.empty())
|
||||
throw amount_error("Commodity specifies more than one tag");
|
||||
throw new amount_error("Commodity specifies more than one tag");
|
||||
|
||||
in.get(c);
|
||||
READ_INTO(in, buf, 255, c, c != ')');
|
||||
if (c == ')')
|
||||
in.get(c);
|
||||
else
|
||||
throw amount_error("Commodity tag lacks closing parenthesis");
|
||||
throw new amount_error("Commodity tag lacks closing parenthesis");
|
||||
tag = buf;
|
||||
if (! added_name) {
|
||||
added_name = true;
|
||||
|
|
@ -1075,7 +1075,7 @@ void amount_t::parse(std::istream& in, unsigned char flags)
|
|||
}
|
||||
|
||||
if (quant.empty())
|
||||
throw amount_error("No quantity specified for amount");
|
||||
throw new amount_error("No quantity specified for amount");
|
||||
|
||||
_init();
|
||||
|
||||
|
|
@ -1794,10 +1794,13 @@ void export_amount()
|
|||
.add_property("commodity",
|
||||
make_function(&amount_t::commodity,
|
||||
return_value_policy<reference_existing_object>()),
|
||||
&amount_t::set_commodity)
|
||||
.add_property("quantity", py_amount_quantity)
|
||||
make_function(&amount_t::set_commodity,
|
||||
with_custodian_and_ward<1, 2>()))
|
||||
|
||||
.def("strip_annotations", &amount_t::strip_annotations)
|
||||
|
||||
.def("negate", &amount_t::negate)
|
||||
.def("negated", &amount_t::negated)
|
||||
.def("parse", py_parse_1)
|
||||
.def("parse", py_parse_2)
|
||||
.def("reduce", &amount_t::reduce)
|
||||
|
|
@ -1816,24 +1819,32 @@ void export_amount()
|
|||
scope().attr("COMMODITY_STYLE_EUROPEAN") = COMMODITY_STYLE_EUROPEAN;
|
||||
scope().attr("COMMODITY_STYLE_THOUSANDS") = COMMODITY_STYLE_THOUSANDS;
|
||||
scope().attr("COMMODITY_STYLE_NOMARKET") = COMMODITY_STYLE_NOMARKET;
|
||||
scope().attr("COMMODITY_STYLE_BUILTIN") = COMMODITY_STYLE_BUILTIN;
|
||||
|
||||
#if 0
|
||||
class_< commodity_t > ("Commodity")
|
||||
.add_property("symbol", &commodity_t::symbol)
|
||||
|
||||
.add_property("name", &commodity_t::name)
|
||||
.add_property("note", &commodity_t::note)
|
||||
.add_property("precision", &commodity_t::precision)
|
||||
.add_property("flags", &commodity_t::flags)
|
||||
#if 0
|
||||
.add_property("name", &commodity_t::name, &commodity_t::set_name)
|
||||
.add_property("note", &commodity_t::note, &commodity_t::set_note)
|
||||
.add_property("precision", &commodity_t::precision,
|
||||
&commodity_t::set_precision)
|
||||
.add_property("flags", &commodity_t::flags, &commodity_t::set_flags)
|
||||
.add_property("add_flags", &commodity_t::add_flags)
|
||||
.add_property("drop_flags", &commodity_t::drop_flags)
|
||||
#if 0
|
||||
.add_property("updater", &commodity_t::updater)
|
||||
#endif
|
||||
|
||||
.add_property("smaller",
|
||||
make_getter(&commodity_t::smaller,
|
||||
return_value_policy<reference_existing_object>()),
|
||||
make_setter(&commodity_t::smaller,
|
||||
return_value_policy<reference_existing_object>()))
|
||||
.add_property("larger",
|
||||
make_getter(&commodity_t::larger,
|
||||
return_value_policy<reference_existing_object>()),
|
||||
make_setter(&commodity_t::larger,
|
||||
return_value_policy<reference_existing_object>()))
|
||||
|
||||
.def(self_ns::str(self))
|
||||
|
|
@ -1841,6 +1852,7 @@ void export_amount()
|
|||
.def("find", py_find_commodity,
|
||||
return_value_policy<reference_existing_object>())
|
||||
.staticmethod("find")
|
||||
#endif
|
||||
|
||||
.def("add_price", &commodity_t::add_price)
|
||||
.def("remove_price", &commodity_t::remove_price)
|
||||
|
|
@ -1848,7 +1860,6 @@ void export_amount()
|
|||
|
||||
.def("valid", &commodity_t::valid)
|
||||
;
|
||||
#endif
|
||||
|
||||
#define EXC_TRANSLATE(type) \
|
||||
register_exception_translator<type>(&exc_translate_ ## type);
|
||||
|
|
|
|||
10
amount.h
10
amount.h
|
|
@ -12,6 +12,7 @@
|
|||
#include <exception>
|
||||
|
||||
#include "debug.h"
|
||||
#include "error.h"
|
||||
|
||||
namespace ledger {
|
||||
|
||||
|
|
@ -624,15 +625,10 @@ inline std::time_t amount_t::date() const {
|
|||
}
|
||||
}
|
||||
|
||||
class amount_error : public std::exception {
|
||||
std::string reason;
|
||||
class amount_error : public error {
|
||||
public:
|
||||
amount_error(const std::string& _reason) throw() : reason(_reason) {}
|
||||
amount_error(const std::string& reason) throw() : error(reason) {}
|
||||
virtual ~amount_error() throw() {}
|
||||
|
||||
virtual const char* what() const throw() {
|
||||
return reason.c_str();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace ledger
|
||||
|
|
|
|||
18
balance.cc
18
balance.cc
|
|
@ -22,7 +22,7 @@ amount_t balance_t::amount(const commodity_t& commodity) const
|
|||
std::ostringstream errmsg;
|
||||
errmsg << "Requested amount of a balance with multiple commodities: "
|
||||
<< *this;
|
||||
throw amount_error(errmsg.str());
|
||||
throw new amount_error(errmsg.str());
|
||||
}
|
||||
}
|
||||
else if (amounts.size() > 0) {
|
||||
|
|
@ -214,7 +214,7 @@ balance_t& balance_t::operator*=(const balance_t& bal)
|
|||
|
||||
std::ostringstream errmsg;
|
||||
errmsg << "Cannot multiply two balances: " << *this << " * " << bal;
|
||||
throw amount_error(errmsg.str());
|
||||
throw new amount_error(errmsg.str());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -255,7 +255,7 @@ balance_t& balance_t::operator*=(const amount_t& amt)
|
|||
errmsg << "Attempt to multiply balance by a commodity"
|
||||
<< " not found in that balance: "
|
||||
<< *this << " * " << amt;
|
||||
throw amount_error(errmsg.str());
|
||||
throw new amount_error(errmsg.str());
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
|
|
@ -266,7 +266,7 @@ balance_t& balance_t::operator/=(const balance_t& bal)
|
|||
if (bal.realzero()) {
|
||||
std::ostringstream errmsg;
|
||||
errmsg << "Attempt to divide by zero: " << *this << " / " << bal;
|
||||
throw amount_error(errmsg.str());
|
||||
throw new amount_error(errmsg.str());
|
||||
}
|
||||
else if (realzero()) {
|
||||
return *this = 0L;
|
||||
|
|
@ -285,7 +285,7 @@ balance_t& balance_t::operator/=(const balance_t& bal)
|
|||
|
||||
std::ostringstream errmsg;
|
||||
errmsg << "Cannot divide between two balances: " << *this << " / " << bal;
|
||||
throw amount_error(errmsg.str());
|
||||
throw new amount_error(errmsg.str());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -294,7 +294,7 @@ balance_t& balance_t::operator/=(const amount_t& amt)
|
|||
if (amt.realzero()) {
|
||||
std::ostringstream errmsg;
|
||||
errmsg << "Attempt to divide by zero: " << *this << " / " << amt;
|
||||
throw amount_error(errmsg.str());
|
||||
throw new amount_error(errmsg.str());
|
||||
}
|
||||
else if (realzero()) {
|
||||
return *this = 0L;
|
||||
|
|
@ -326,7 +326,7 @@ balance_t& balance_t::operator/=(const amount_t& amt)
|
|||
errmsg << "Attempt to divide balance by a commodity"
|
||||
<< " not found in that balance: "
|
||||
<< *this << " * " << amt;
|
||||
throw amount_error(errmsg.str());
|
||||
throw new amount_error(errmsg.str());
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
|
|
@ -349,7 +349,7 @@ balance_t::operator amount_t() const
|
|||
std::ostringstream errmsg;
|
||||
errmsg << "Cannot convert a balance with "
|
||||
<< "multiple commodities to an amount: " << *this;
|
||||
throw amount_error(errmsg.str());
|
||||
throw new amount_error(errmsg.str());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -464,7 +464,6 @@ void export_balance()
|
|||
.def("date", &balance_t::date)
|
||||
.def("strip_annotations", &balance_t::strip_annotations)
|
||||
.def("write", &balance_t::write)
|
||||
.def("abs", &balance_t::abs)
|
||||
.def("round", &balance_t::round)
|
||||
.def("negate", &balance_t::negate)
|
||||
.def("negated", &balance_t::negated)
|
||||
|
|
@ -553,7 +552,6 @@ void export_balance()
|
|||
.def("date", &balance_pair_t::date)
|
||||
.def("strip_annotations", &balance_pair_t::strip_annotations)
|
||||
.def("write", &balance_pair_t::write)
|
||||
.def("abs", &balance_pair_t::abs)
|
||||
.def("round", &balance_pair_t::round)
|
||||
.def("negate", &balance_pair_t::negate)
|
||||
.def("negated", &balance_pair_t::negated)
|
||||
|
|
|
|||
17
balance.h
17
balance.h
|
|
@ -416,6 +416,16 @@ class balance_t
|
|||
if ((*i).second.commodity())
|
||||
(*i).second = (*i).second.round();
|
||||
}
|
||||
|
||||
balance_t unround() const {
|
||||
balance_t temp;
|
||||
for (amounts_map::const_iterator i = amounts.begin();
|
||||
i != amounts.end();
|
||||
i++)
|
||||
if ((*i).second.commodity())
|
||||
temp += (*i).second.unround();
|
||||
return temp;
|
||||
}
|
||||
};
|
||||
|
||||
inline balance_t abs(const balance_t& bal) {
|
||||
|
|
@ -847,6 +857,13 @@ class balance_pair_t
|
|||
quantity.round();
|
||||
if (cost) cost->round();
|
||||
}
|
||||
|
||||
balance_pair_t unround() {
|
||||
balance_pair_t temp(quantity.unround());
|
||||
if (cost)
|
||||
temp.cost = new balance_t(cost->unround());
|
||||
return temp;
|
||||
}
|
||||
};
|
||||
|
||||
inline balance_pair_t abs(const balance_pair_t& bal_pair) {
|
||||
|
|
|
|||
32
binary.cc
32
binary.cc
|
|
@ -621,9 +621,29 @@ unsigned int read_binary_journal(std::istream& in,
|
|||
std::pair<base_commodities_map::iterator, bool> result =
|
||||
commodity_base_t::commodities.insert
|
||||
(base_commodities_pair(commodity->symbol, commodity));
|
||||
if (! result.second)
|
||||
throw error(std::string("Failed to read base commodity from cache: ") +
|
||||
commodity->symbol);
|
||||
if (! result.second) {
|
||||
base_commodities_map::iterator c =
|
||||
commodity_base_t::commodities.find(commodity->symbol);
|
||||
|
||||
// It's possible the user might have used a commodity in a value
|
||||
// expression passed to an option, we'll just override the
|
||||
// flags, but keep the commodity pointer intact.
|
||||
if (c == commodity_base_t::commodities.end() ||
|
||||
(*c).second->history || (*c).second->smaller ||
|
||||
(*c).second->larger)
|
||||
throw new error(std::string("Failed to read base commodity from cache: ") +
|
||||
commodity->symbol);
|
||||
|
||||
(*c).second->name = commodity->name;
|
||||
(*c).second->note = commodity->note;
|
||||
(*c).second->precision = commodity->precision;
|
||||
(*c).second->flags = commodity->flags;
|
||||
(*c).second->history = commodity->history;
|
||||
(*c).second->smaller = commodity->smaller;
|
||||
(*c).second->larger = commodity->larger;
|
||||
|
||||
*(base_commodities_next - 1) = (*c).second;
|
||||
}
|
||||
}
|
||||
|
||||
for (commodity_base_t::ident_t i = 0; i < bc_count; i++)
|
||||
|
|
@ -655,9 +675,9 @@ unsigned int read_binary_journal(std::istream& in,
|
|||
std::pair<commodities_map::iterator, bool> result =
|
||||
commodity_t::commodities.insert(commodities_pair(mapping_key,
|
||||
commodity));
|
||||
if (! result.second)
|
||||
throw error(std::string("Failed to read commodity from cache: ") +
|
||||
commodity->ptr->symbol);
|
||||
if (! result.second && commodity->annotated)
|
||||
throw new error(std::string("Failed to read commodity from cache: ") +
|
||||
commodity->ptr->symbol);
|
||||
}
|
||||
|
||||
commodity_t::ident_t ident;
|
||||
|
|
|
|||
63
config.cc
63
config.cc
|
|
@ -52,8 +52,9 @@ namespace {
|
|||
|
||||
void config_t::reset()
|
||||
{
|
||||
amount_expr = "a";
|
||||
total_expr = "O";
|
||||
ledger::amount_expr.reset(new value_expr("a"));
|
||||
ledger::total_expr.reset(new value_expr("O"));
|
||||
|
||||
pricing_leeway = 24 * 3600;
|
||||
budget_flags = BUDGET_NO_BUDGET;
|
||||
balance_format = "%20T %2_%-a\n";
|
||||
|
|
@ -293,8 +294,10 @@ void config_t::process_options(const std::string& command,
|
|||
|
||||
// Setup the values of %t and %T, used in format strings
|
||||
|
||||
ledger::amount_expr.reset(new value_expr(amount_expr));
|
||||
ledger::total_expr.reset(new value_expr(total_expr));
|
||||
if (! amount_expr.empty())
|
||||
ledger::amount_expr.reset(new value_expr(amount_expr));
|
||||
if (! total_expr.empty())
|
||||
ledger::total_expr.reset(new value_expr(total_expr));
|
||||
|
||||
// If downloading is to be supported, configure the updater
|
||||
|
||||
|
|
@ -699,8 +702,8 @@ OPT_BEGIN(file, "f:") {
|
|||
if (std::string(optarg) == "-" || access(optarg, R_OK) != -1)
|
||||
config->data_file = optarg;
|
||||
else
|
||||
throw error(std::string("The ledger file '") + optarg +
|
||||
"' does not exist or is not readable");
|
||||
throw new error(std::string("The ledger file '") + optarg +
|
||||
"' does not exist or is not readable");
|
||||
} OPT_END(file);
|
||||
|
||||
OPT_BEGIN(cache, ":") {
|
||||
|
|
@ -747,8 +750,8 @@ OPT_BEGIN(begin, "b:") {
|
|||
if (interval.begin)
|
||||
std::strftime(buf, 127, formats[0], std::localtime(&interval.begin));
|
||||
else
|
||||
throw error(std::string("Could not determine beginning of period '") +
|
||||
optarg + "'");
|
||||
throw new error(std::string("Could not determine beginning of period '") +
|
||||
optarg + "'");
|
||||
|
||||
if (! config->predicate.empty())
|
||||
config->predicate += "&";
|
||||
|
|
@ -763,8 +766,8 @@ OPT_BEGIN(end, "e:") {
|
|||
if (interval.end)
|
||||
std::strftime(buf, 127, formats[0], std::localtime(&interval.end));
|
||||
else
|
||||
throw error(std::string("Could not determine end of period '") +
|
||||
optarg + "'");
|
||||
throw new error(std::string("Could not determine end of period '") +
|
||||
optarg + "'");
|
||||
|
||||
if (! config->predicate.empty())
|
||||
config->predicate += "&";
|
||||
|
|
@ -1048,11 +1051,11 @@ OPT_BEGIN(display, "d:") {
|
|||
} OPT_END(display);
|
||||
|
||||
OPT_BEGIN(amount, "t:") {
|
||||
config->amount_expr = optarg;
|
||||
ledger::amount_expr.reset(new value_expr(optarg));
|
||||
} OPT_END(amount);
|
||||
|
||||
OPT_BEGIN(total, "T:") {
|
||||
config->total_expr = optarg;
|
||||
ledger::total_expr.reset(new value_expr(optarg));
|
||||
} OPT_END(total);
|
||||
|
||||
OPT_BEGIN(amount_data, "j") {
|
||||
|
|
@ -1080,50 +1083,56 @@ OPT_BEGIN(download, "Q") {
|
|||
} OPT_END(download);
|
||||
|
||||
OPT_BEGIN(quantity, "O") {
|
||||
config->amount_expr = "a";
|
||||
config->total_expr = "O";
|
||||
ledger::amount_expr.reset(new value_expr("a"));
|
||||
ledger::total_expr.reset(new value_expr("O"));
|
||||
} OPT_END(quantity);
|
||||
|
||||
OPT_BEGIN(basis, "B") {
|
||||
config->amount_expr = "b";
|
||||
config->total_expr = "B";
|
||||
ledger::amount_expr.reset(new value_expr("b"));
|
||||
ledger::total_expr.reset(new value_expr("B"));
|
||||
} OPT_END(basis);
|
||||
|
||||
OPT_BEGIN(price, "I") {
|
||||
config->amount_expr = "i";
|
||||
config->total_expr = "I";
|
||||
ledger::amount_expr.reset(new value_expr("i"));
|
||||
ledger::total_expr.reset(new value_expr("I"));
|
||||
} OPT_END(price);
|
||||
|
||||
OPT_BEGIN(market, "V") {
|
||||
config->show_revalued = true;
|
||||
|
||||
config->amount_expr = "v";
|
||||
config->total_expr = "V";
|
||||
ledger::amount_expr.reset(new value_expr("v"));
|
||||
ledger::total_expr.reset(new value_expr("V"));
|
||||
} OPT_END(market);
|
||||
|
||||
OPT_BEGIN(performance, "g") {
|
||||
config->amount_expr = "P(a,m)-b"; // same as 'g', but priced now
|
||||
config->total_expr = "P(O,m)-B";
|
||||
ledger::amount_expr.reset(new value_expr("P(a,m)-b"));
|
||||
ledger::total_expr.reset(new value_expr("P(O,m)-B"));
|
||||
} OPT_END(performance);
|
||||
|
||||
OPT_BEGIN(gain, "G") {
|
||||
config->show_revalued =
|
||||
config->show_revalued_only = true;
|
||||
|
||||
config->amount_expr = "a";
|
||||
config->total_expr = "G";
|
||||
ledger::amount_expr.reset(new value_expr("a"));
|
||||
ledger::total_expr.reset(new value_expr("G"));
|
||||
} OPT_END(gain);
|
||||
|
||||
OPT_BEGIN(average, "A") {
|
||||
config->total_expr = expand_value_expr("A(#)", config->total_expr);
|
||||
ledger::total_expr.reset
|
||||
(new value_expr(expand_value_expr("A(#)", ledger::total_expr->expr)));
|
||||
} OPT_END(average);
|
||||
|
||||
OPT_BEGIN(deviation, "D") {
|
||||
config->total_expr = expand_value_expr("t-A(#)", config->total_expr);
|
||||
ledger::total_expr.reset(new value_expr("O"));
|
||||
ledger::total_expr.reset
|
||||
(new value_expr(expand_value_expr("t-A(#)", ledger::total_expr->expr)));
|
||||
} OPT_END(deviation);
|
||||
|
||||
OPT_BEGIN(percentage, "%") {
|
||||
config->total_expr = expand_value_expr("^#&{100.0%}*(#/^#)", config->total_expr);
|
||||
ledger::total_expr.reset(new value_expr("O"));
|
||||
ledger::total_expr.reset
|
||||
(new value_expr(expand_value_expr("^#&{100.0%}*(#/^#)",
|
||||
ledger::total_expr->expr)));
|
||||
} OPT_END(percentage);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@ static void parse_inclusion_specifier(const std::string& word,
|
|||
struct std::tm when;
|
||||
|
||||
if (! parse_date_mask(word.c_str(), &when))
|
||||
throw datetime_error(std::string("Could not parse date mask: ") + word);
|
||||
throw new datetime_error(std::string("Could not parse date mask: ") + word);
|
||||
|
||||
when.tm_hour = 0;
|
||||
when.tm_min = 0;
|
||||
|
|
|
|||
15
datetime.h
15
datetime.h
|
|
@ -4,6 +4,8 @@
|
|||
#include <ctime>
|
||||
#include <sstream>
|
||||
|
||||
#include "error.h"
|
||||
|
||||
struct interval_t;
|
||||
|
||||
struct datetime_t
|
||||
|
|
@ -69,6 +71,10 @@ inline std::ostream& operator<<(std::ostream& out, const datetime_t& moment) {
|
|||
out << buf;
|
||||
}
|
||||
|
||||
inline long operator-(const datetime_t& left, const datetime_t& right) {
|
||||
return (long)left.when - (long)right.when;
|
||||
}
|
||||
|
||||
struct interval_t
|
||||
{
|
||||
unsigned int years;
|
||||
|
|
@ -120,15 +126,10 @@ bool parse_date(const char * date_str, std::time_t * result,
|
|||
const int year = -1);
|
||||
bool quick_parse_date(const char * date_str, std::time_t * result);
|
||||
|
||||
class datetime_error : public std::exception {
|
||||
std::string reason;
|
||||
class datetime_error : public error {
|
||||
public:
|
||||
datetime_error(const std::string& _reason) throw() : reason(_reason) {}
|
||||
datetime_error(const std::string& reason) throw() : error(reason) {}
|
||||
virtual ~datetime_error() throw() {}
|
||||
|
||||
virtual const char* what() const throw() {
|
||||
return reason.c_str();
|
||||
}
|
||||
};
|
||||
|
||||
#endif // _DATETIME_H
|
||||
|
|
|
|||
15
debug.cc
15
debug.cc
|
|
@ -4,8 +4,6 @@
|
|||
|
||||
#include <map>
|
||||
#include <fstream>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
#include <unistd.h> // for the `write' method
|
||||
|
||||
|
|
@ -112,3 +110,16 @@ static struct init_streams {
|
|||
} _debug_init;
|
||||
|
||||
#endif // DEBUG_ENABLED
|
||||
|
||||
#if DEBUG_LEVEL >= BETA
|
||||
|
||||
#include <string>
|
||||
|
||||
void debug_assert(const std::string& reason,
|
||||
const std::string& file,
|
||||
unsigned long line)
|
||||
{
|
||||
throw new fatal_assert(reason, new file_context(file, line));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
25
debug.h
25
debug.h
|
|
@ -12,7 +12,28 @@
|
|||
#endif
|
||||
|
||||
#if DEBUG_LEVEL >= RELEASE
|
||||
#include <cassert>
|
||||
#include "error.h"
|
||||
|
||||
#ifdef assert
|
||||
#undef assert
|
||||
#endif
|
||||
#if DEBUG_LEVEL >= BETA
|
||||
void debug_assert(const std::string& reason,
|
||||
const std::string& file,
|
||||
unsigned long line);
|
||||
#define assert(x) \
|
||||
if (! (x)) \
|
||||
debug_assert(#x, __FILE__, __LINE__)
|
||||
#else
|
||||
#define assert(x) \
|
||||
if (! (x)) \
|
||||
throw new fatal_assert(#x, new file_context(__FILE__, __LINE__))
|
||||
#endif
|
||||
#else
|
||||
#ifdef assert
|
||||
#undef assert
|
||||
#endif
|
||||
#define assert(x)
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -105,7 +126,9 @@ void operator delete[](void*, const std::nothrow_t&) throw();
|
|||
|
||||
#if DEBUG_LEVEL == NO_SEATBELT
|
||||
|
||||
#ifdef assert
|
||||
#undef assert
|
||||
#endif
|
||||
#define assert(x)
|
||||
#define CONFIRM(x)
|
||||
|
||||
|
|
|
|||
|
|
@ -17,10 +17,10 @@ entry_t * derive_new_entry(journal_t& journal,
|
|||
entry_t * matching = NULL;
|
||||
|
||||
if (! parse_date((*i).c_str(), &added->_date))
|
||||
throw error("Bad date passed to 'entry'");
|
||||
throw new error("Bad date passed to 'entry'");
|
||||
|
||||
if (++i == end)
|
||||
throw error("Too few arguments to 'entry'");
|
||||
throw new error("Too few arguments to 'entry'");
|
||||
|
||||
mask_t regexp(*i++);
|
||||
|
||||
|
|
@ -169,7 +169,7 @@ entry_t * derive_new_entry(journal_t& journal,
|
|||
done:
|
||||
if (! run_hooks(journal.entry_finalize_hooks, *added) ||
|
||||
! added->finalize())
|
||||
throw error("Failed to finalize derived entry (check commodities)");
|
||||
throw new error("Failed to finalize derived entry (check commodities)");
|
||||
|
||||
return added.release();
|
||||
}
|
||||
|
|
|
|||
208
error.h
208
error.h
|
|
@ -1,63 +1,231 @@
|
|||
#ifndef _ERROR_H
|
||||
#define _ERROR_H
|
||||
|
||||
#include "journal.h"
|
||||
|
||||
#include <exception>
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
#include <sstream>
|
||||
#include <list>
|
||||
|
||||
namespace ledger {
|
||||
class error_context
|
||||
{
|
||||
public:
|
||||
std::string desc;
|
||||
|
||||
class error : public std::exception {
|
||||
error_context(const std::string& _desc) throw() : desc(_desc) {}
|
||||
virtual ~error_context() throw() {}
|
||||
virtual void describe(std::ostream& out) const throw() {
|
||||
if (! desc.empty())
|
||||
out << desc << std::endl;
|
||||
}
|
||||
};
|
||||
|
||||
class file_context : public error_context
|
||||
{
|
||||
protected:
|
||||
std::string file;
|
||||
unsigned long line;
|
||||
public:
|
||||
file_context(const std::string& _file, unsigned long _line,
|
||||
const std::string& desc = "") throw()
|
||||
: file(_file), line(_line), error_context(desc) {}
|
||||
virtual ~file_context() throw() {}
|
||||
|
||||
virtual void describe(std::ostream& out) const throw() {
|
||||
if (! desc.empty())
|
||||
out << desc << " ";
|
||||
|
||||
out << "\"" << file << "\", line " << line << ": ";
|
||||
}
|
||||
};
|
||||
|
||||
namespace ledger { class value_t; }
|
||||
class value_context : public error_context
|
||||
{
|
||||
ledger::value_t * bal;
|
||||
public:
|
||||
value_context(const ledger::value_t& _bal,
|
||||
const std::string& desc = "") throw();
|
||||
virtual ~value_context() throw();
|
||||
|
||||
virtual void describe(std::ostream& out) const throw();
|
||||
};
|
||||
|
||||
namespace ledger { class value_expr_t; }
|
||||
class valexpr_context : public error_context {
|
||||
public:
|
||||
const ledger::value_expr_t * expr;
|
||||
const ledger::value_expr_t * error_node;
|
||||
|
||||
valexpr_context(const ledger::value_expr_t * _expr,
|
||||
const std::string& desc = "") throw();
|
||||
virtual ~valexpr_context() throw();
|
||||
|
||||
virtual void describe(std::ostream& out) const throw();
|
||||
};
|
||||
|
||||
class line_context : public error_context {
|
||||
public:
|
||||
std::string line;
|
||||
long pos;
|
||||
|
||||
line_context(const std::string& _line, long _pos,
|
||||
const std::string& desc = "") throw()
|
||||
: line(_line), pos(_pos), error_context(desc) {}
|
||||
virtual ~line_context() throw() {}
|
||||
|
||||
virtual void describe(std::ostream& out) const throw();
|
||||
};
|
||||
|
||||
class include_context : public file_context {
|
||||
public:
|
||||
include_context(const std::string& file, unsigned long line,
|
||||
const std::string& desc = "") throw()
|
||||
: file_context(file, line, desc) {}
|
||||
virtual ~include_context() throw() {}
|
||||
|
||||
virtual void describe(std::ostream& out) const throw() {
|
||||
if (! desc.empty())
|
||||
out << desc << ": ";
|
||||
out << "\"" << file << "\", line " << line << ":" << std::endl;
|
||||
}
|
||||
};
|
||||
|
||||
namespace ledger { class entry_base_t; }
|
||||
class entry_context : public error_context {
|
||||
public:
|
||||
const ledger::entry_base_t& entry;
|
||||
|
||||
entry_context(const ledger::entry_base_t& _entry,
|
||||
const std::string& desc = "") throw()
|
||||
: entry(_entry), error_context(desc) {}
|
||||
virtual ~entry_context() throw() {}
|
||||
|
||||
virtual void describe(std::ostream& out) const throw();
|
||||
};
|
||||
|
||||
namespace ledger { class transaction_t; }
|
||||
class xact_context : public file_context {
|
||||
public:
|
||||
const ledger::transaction_t& xact;
|
||||
|
||||
xact_context(const ledger::transaction_t& _xact,
|
||||
const std::string& desc = "") throw();
|
||||
virtual ~xact_context() throw() {}
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
class str_exception : public std::exception {
|
||||
protected:
|
||||
std::string reason;
|
||||
public:
|
||||
error(const std::string& _reason) throw() : reason(_reason) {}
|
||||
virtual ~error() throw() {}
|
||||
std::list<error_context *> context;
|
||||
|
||||
str_exception(const std::string& _reason,
|
||||
error_context * ctxt = NULL) throw()
|
||||
: reason(_reason) {
|
||||
if (ctxt)
|
||||
context.push_back(ctxt);
|
||||
}
|
||||
|
||||
virtual ~str_exception() throw() {
|
||||
for (std::list<error_context *>::iterator i = context.begin();
|
||||
i != context.end();
|
||||
i++)
|
||||
delete *i;
|
||||
}
|
||||
|
||||
virtual void reveal_context(std::ostream& out,
|
||||
const std::string& kind) const throw() {
|
||||
for (std::list<error_context *>::const_reverse_iterator i =
|
||||
context.rbegin();
|
||||
i != context.rend();
|
||||
i++) {
|
||||
std::list<error_context *>::const_reverse_iterator x = i;
|
||||
if (++x == context.rend())
|
||||
out << kind << ": ";
|
||||
(*i)->describe(out);
|
||||
}
|
||||
}
|
||||
|
||||
virtual const char* what() const throw() {
|
||||
return reason.c_str();
|
||||
}
|
||||
};
|
||||
|
||||
class error : public str_exception {
|
||||
public:
|
||||
error(const std::string& reason, error_context * ctxt = NULL) throw()
|
||||
: str_exception(reason, ctxt) {}
|
||||
virtual ~error() throw() {}
|
||||
};
|
||||
|
||||
class fatal : public str_exception {
|
||||
public:
|
||||
fatal(const std::string& reason, error_context * ctxt = NULL) throw()
|
||||
: str_exception(reason, ctxt) {}
|
||||
virtual ~fatal() throw() {}
|
||||
};
|
||||
|
||||
class fatal_assert : public fatal {
|
||||
public:
|
||||
fatal_assert(const std::string& reason, error_context * ctxt = NULL) throw()
|
||||
: fatal(std::string("assertion failed '") + reason + "'", ctxt) {}
|
||||
virtual ~fatal_assert() throw() {}
|
||||
};
|
||||
|
||||
namespace ledger {
|
||||
|
||||
class compute_error : public error {
|
||||
public:
|
||||
compute_error(const std::string& reason) throw() : error(reason) {}
|
||||
compute_error(const std::string& reason, error_context * ctxt = NULL) throw()
|
||||
: error(reason, ctxt) {}
|
||||
virtual ~compute_error() throw() {}
|
||||
};
|
||||
|
||||
class value_expr_error : public error {
|
||||
public:
|
||||
value_expr_error(const std::string& reason) throw() : error(reason) {}
|
||||
value_expr_error(const std::string& reason,
|
||||
error_context * ctxt = NULL) throw()
|
||||
: error(reason, ctxt) {}
|
||||
virtual ~value_expr_error() throw() {}
|
||||
};
|
||||
|
||||
class interval_expr_error : public error {
|
||||
public:
|
||||
interval_expr_error(const std::string& reason) throw() : error(reason) {}
|
||||
interval_expr_error(const std::string& reason,
|
||||
error_context * ctxt = NULL) throw()
|
||||
: error(reason, ctxt) {}
|
||||
virtual ~interval_expr_error() throw() {}
|
||||
};
|
||||
|
||||
class format_error : public error {
|
||||
public:
|
||||
format_error(const std::string& reason) throw() : error(reason) {}
|
||||
format_error(const std::string& reason, error_context * ctxt = NULL) throw()
|
||||
: error(reason, ctxt) {}
|
||||
virtual ~format_error() throw() {}
|
||||
};
|
||||
|
||||
class parse_error : public error {
|
||||
unsigned int line;
|
||||
std::string file;
|
||||
public:
|
||||
parse_error(const std::string& _file, const unsigned int _line,
|
||||
const std::string& reason) throw()
|
||||
: error(reason), line(_line), file(_file) {}
|
||||
parse_error(const std::string& reason, error_context * ctxt = NULL) throw()
|
||||
: error(reason, ctxt) {}
|
||||
virtual ~parse_error() throw() {}
|
||||
};
|
||||
|
||||
virtual const char* what() const throw() {
|
||||
std::ostringstream msg;
|
||||
msg << file << ", line " << line << ": " << error::what();
|
||||
return msg.str().c_str();
|
||||
}
|
||||
class value_error : public error {
|
||||
public:
|
||||
value_error(const std::string& reason, error_context * ctxt = NULL) throw()
|
||||
: error(reason, ctxt) {}
|
||||
virtual ~value_error() throw() {}
|
||||
};
|
||||
|
||||
class balance_error : public error {
|
||||
public:
|
||||
balance_error(const std::string& reason, error_context * ctxt = NULL) throw()
|
||||
: error(reason, ctxt) {}
|
||||
virtual ~balance_error() throw() {}
|
||||
};
|
||||
|
||||
} // namespace ledger
|
||||
|
|
|
|||
35
format.cc
35
format.cc
|
|
@ -157,7 +157,7 @@ element_t * format_t::parse_elements(const std::string& fmt)
|
|||
p++;
|
||||
}
|
||||
if (*p != ')')
|
||||
throw format_error("Missing ')'");
|
||||
throw new format_error("Missing ')'");
|
||||
|
||||
current->type = element_t::VALUE_EXPR;
|
||||
|
||||
|
|
@ -178,7 +178,7 @@ element_t * format_t::parse_elements(const std::string& fmt)
|
|||
p++;
|
||||
}
|
||||
if (*p != ']')
|
||||
throw format_error("Missing ']'");
|
||||
throw new format_error("Missing ']'");
|
||||
|
||||
current->type = element_t::DATE_STRING;
|
||||
current->chars = std::string(b, p);
|
||||
|
|
@ -287,7 +287,7 @@ void format_t::format(std::ostream& out_str, const details_t& details) const
|
|||
case element_t::AMOUNT:
|
||||
case element_t::TOTAL:
|
||||
case element_t::VALUE_EXPR: {
|
||||
value_calc * calc = NULL;
|
||||
value_expr * calc = NULL;
|
||||
switch (elem->type) {
|
||||
case element_t::AMOUNT: calc = amount_expr.get(); break;
|
||||
case element_t::TOTAL: calc = total_expr.get(); break;
|
||||
|
|
@ -681,18 +681,37 @@ void format_entries::operator()(transaction_t& xact)
|
|||
last_entry = xact.entry;
|
||||
}
|
||||
|
||||
void print_entry(std::ostream& out, const entry_t& entry)
|
||||
void print_entry(std::ostream& out, const entry_base_t& entry_base,
|
||||
const std::string& prefix)
|
||||
{
|
||||
const std::string print_format
|
||||
= "\n%D %X%C%P\n %-34A %12o\n%/ %-34A %12o\n";
|
||||
std::string print_format;
|
||||
|
||||
if (const entry_t * entry = dynamic_cast<const entry_t *>(&entry_base)) {
|
||||
print_format = (prefix + "%D %X%C%P\n" +
|
||||
prefix + " %-34A %12o\n%/" +
|
||||
prefix + " %-34A %12o\n");
|
||||
}
|
||||
else if (const auto_entry_t * entry =
|
||||
dynamic_cast<const auto_entry_t *>(&entry_base)) {
|
||||
out << "= " << entry->predicate_string << '\n';
|
||||
print_format = prefix + " %-34A %12o\n";
|
||||
}
|
||||
else if (const period_entry_t * entry =
|
||||
dynamic_cast<const period_entry_t *>(&entry_base)) {
|
||||
out << "~ " << entry->period_string << '\n';
|
||||
print_format = prefix + " %-34A %12o\n";
|
||||
}
|
||||
else {
|
||||
assert(0);
|
||||
}
|
||||
|
||||
format_entries formatter(out, print_format);
|
||||
walk_transactions(const_cast<transactions_list&>(entry.transactions),
|
||||
walk_transactions(const_cast<transactions_list&>(entry_base.transactions),
|
||||
formatter);
|
||||
formatter.flush();
|
||||
|
||||
clear_transaction_xdata cleaner;
|
||||
walk_transactions(const_cast<transactions_list&>(entry.transactions),
|
||||
walk_transactions(const_cast<transactions_list&>(entry_base.transactions),
|
||||
cleaner);
|
||||
}
|
||||
|
||||
|
|
|
|||
3
format.h
3
format.h
|
|
@ -133,7 +133,8 @@ class format_entries : public format_transactions
|
|||
virtual void operator()(transaction_t& xact);
|
||||
};
|
||||
|
||||
void print_entry(std::ostream& out, const entry_t& entry);
|
||||
void print_entry(std::ostream& out, const entry_base_t& entry,
|
||||
const std::string& prefix = "");
|
||||
|
||||
bool disp_subaccounts_p(const account_t& account,
|
||||
const item_predicate<account_t>& disp_pred,
|
||||
|
|
|
|||
|
|
@ -415,12 +415,12 @@ unsigned int gnucash_parser_t::parse(std::istream& in,
|
|||
unsigned long line = XML_GetCurrentLineNumber(parser) - offset++;
|
||||
const char * msg = XML_ErrorString(XML_GetErrorCode(parser));
|
||||
XML_ParserFree(parser);
|
||||
throw parse_error(path, line, msg);
|
||||
throw new parse_error(msg);
|
||||
}
|
||||
|
||||
if (! have_error.empty()) {
|
||||
unsigned long line = XML_GetCurrentLineNumber(parser) - offset++;
|
||||
parse_error err(path, line, have_error);
|
||||
parse_error err(have_error);
|
||||
std::cerr << "Error: " << err.what() << std::endl;
|
||||
have_error = "";
|
||||
}
|
||||
|
|
|
|||
18
journal.cc
18
journal.cc
|
|
@ -79,15 +79,13 @@ bool entry_base_t::remove_transaction(transaction_t * xact)
|
|||
return true;
|
||||
}
|
||||
|
||||
value_t entry_balance;
|
||||
|
||||
bool entry_base_t::finalize()
|
||||
{
|
||||
// Scan through and compute the total balance for the entry. This
|
||||
// is used for auto-calculating the value of entries with no cost,
|
||||
// and the per-unit price of unpriced commodities.
|
||||
|
||||
value_t& balance = entry_balance;
|
||||
value_t balance;
|
||||
|
||||
bool no_amounts = true;
|
||||
for (transactions_list::const_iterator x = transactions.begin();
|
||||
|
|
@ -106,7 +104,8 @@ bool entry_base_t::finalize()
|
|||
|
||||
if ((*x)->cost && (*x)->amount.commodity().annotated) {
|
||||
annotated_commodity_t&
|
||||
ann_comm(static_cast<annotated_commodity_t&>((*x)->amount.commodity()));
|
||||
ann_comm(static_cast<annotated_commodity_t&>
|
||||
((*x)->amount.commodity()));
|
||||
if (ann_comm.price)
|
||||
balance += ann_comm.price * (*x)->amount - *((*x)->cost);
|
||||
}
|
||||
|
|
@ -240,7 +239,16 @@ bool entry_base_t::finalize()
|
|||
}
|
||||
}
|
||||
|
||||
return ! balance;
|
||||
if (balance) {
|
||||
error * err =
|
||||
new balance_error("Entry does not balance",
|
||||
new entry_context(*this, "While balancing entry:"));
|
||||
err->context.push_front
|
||||
(new value_context(balance, "Unbalanced remainder is:"));
|
||||
throw err;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
entry_t::entry_t(const entry_t& e)
|
||||
|
|
|
|||
|
|
@ -151,8 +151,6 @@ class entry_base_t
|
|||
virtual bool valid() const = 0;
|
||||
};
|
||||
|
||||
extern value_t entry_balance;
|
||||
|
||||
class entry_t : public entry_base_t
|
||||
{
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
@dircategory User Applications
|
||||
@copying
|
||||
Copyright (c) 2003-2004, John Wiegley. All rights reserved.
|
||||
Copyright (c) 2003-2006, John Wiegley. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
|
|
|
|||
63
main.cc
63
main.cc
|
|
@ -121,11 +121,16 @@ int parse_and_report(config_t& config, int argc, char * argv[], char * envp[])
|
|||
else if (command == "parse") {
|
||||
value_auto_ptr expr(ledger::parse_value_expr(*arg));
|
||||
if (config.verbose_mode) {
|
||||
std::cout << "Value expression tree:" << std::endl;
|
||||
ledger::dump_value_expr(std::cout, expr.get());
|
||||
std::cout << std::endl;
|
||||
std::cout << "Value expression parsed was:" << std::endl;
|
||||
ledger::write_value_expr(std::cout, expr.get());
|
||||
std::cout << std::endl << std::endl;
|
||||
std::cout << "Result of computation: ";
|
||||
}
|
||||
value_t result = guarded_compute(expr.get());
|
||||
|
||||
value_t result = expr->compute();
|
||||
if (! config.keep_price || ! config.keep_date || ! config.keep_tag) {
|
||||
switch (result.type) {
|
||||
case value_t::AMOUNT:
|
||||
|
|
@ -138,13 +143,15 @@ int parse_and_report(config_t& config, int argc, char * argv[], char * envp[])
|
|||
}
|
||||
}
|
||||
std::cout << result << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
else if (command == "expr") {
|
||||
// this gets done below...
|
||||
}
|
||||
else
|
||||
throw error(std::string("Unrecognized command '") + command + "'");
|
||||
else {
|
||||
throw new error(std::string("Unrecognized command '") + command + "'");
|
||||
}
|
||||
|
||||
// Parse initialization files, ledger data, price database, etc.
|
||||
|
||||
|
|
@ -153,8 +160,8 @@ int parse_and_report(config_t& config, int argc, char * argv[], char * envp[])
|
|||
{ TRACE_PUSH(parser, "Parsing journal file");
|
||||
|
||||
if (parse_ledger_data(config, journal.get()) == 0)
|
||||
throw error("Please specify ledger file using -f"
|
||||
" or LEDGER_FILE environment variable.");
|
||||
throw new error("Please specify ledger file using -f"
|
||||
" or LEDGER_FILE environment variable.");
|
||||
|
||||
TRACE_POP(parser, "Finished parsing"); }
|
||||
|
||||
|
|
@ -163,7 +170,7 @@ int parse_and_report(config_t& config, int argc, char * argv[], char * envp[])
|
|||
std::string first_arg;
|
||||
if (command == "w") {
|
||||
if (arg == args.end())
|
||||
throw error("The 'output' command requires a file argument");
|
||||
throw new error("The 'output' command requires a file argument");
|
||||
first_arg = *arg++;
|
||||
}
|
||||
|
||||
|
|
@ -193,11 +200,11 @@ int parse_and_report(config_t& config, int argc, char * argv[], char * envp[])
|
|||
else if (! config.pager.empty()) {
|
||||
status = pipe(pfd);
|
||||
if (status == -1)
|
||||
throw error("Failed to create pipe");
|
||||
throw new error("Failed to create pipe");
|
||||
|
||||
status = fork();
|
||||
if (status < 0) {
|
||||
throw error("Failed to fork child process");
|
||||
throw new error("Failed to fork child process");
|
||||
}
|
||||
else if (status == 0) { // child
|
||||
const char *arg0;
|
||||
|
|
@ -238,10 +245,16 @@ int parse_and_report(config_t& config, int argc, char * argv[], char * envp[])
|
|||
if (command == "expr") {
|
||||
value_auto_ptr expr(ledger::parse_value_expr(*arg));
|
||||
if (config.verbose_mode) {
|
||||
std::cout << "Value expression tree:" << std::endl;
|
||||
ledger::dump_value_expr(std::cout, expr.get());
|
||||
std::cout << std::endl;
|
||||
std::cout << "Value expression parsed was:" << std::endl;
|
||||
ledger::write_value_expr(std::cout, expr.get(), NULL, 0);
|
||||
std::cout << std::endl << std::endl;
|
||||
std::cout << "Result of computation: ";
|
||||
}
|
||||
value_t result = expr->compute();
|
||||
value_t result = guarded_compute(expr.get());
|
||||
|
||||
if (! config.keep_price || ! config.keep_date || ! config.keep_tag) {
|
||||
switch (result.type) {
|
||||
case value_t::AMOUNT:
|
||||
|
|
@ -254,6 +267,7 @@ int parse_and_report(config_t& config, int argc, char * argv[], char * envp[])
|
|||
}
|
||||
}
|
||||
std::cout << result << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -293,7 +307,7 @@ int parse_and_report(config_t& config, int argc, char * argv[], char * envp[])
|
|||
#if defined(HAVE_EXPAT) || defined(HAVE_XMLPARSE)
|
||||
formatter = new format_xml_entries(*out, config.show_totals);
|
||||
#else
|
||||
throw error("XML support was not compiled into this copy of Ledger");
|
||||
throw new error("XML support was not compiled into this copy of Ledger");
|
||||
#endif
|
||||
} else
|
||||
formatter = new format_transactions(*out, *format);
|
||||
|
|
@ -392,7 +406,7 @@ int parse_and_report(config_t& config, int argc, char * argv[], char * envp[])
|
|||
// Wait for child to finish
|
||||
wait(&status);
|
||||
if (status & 0xffff != 0)
|
||||
throw error("Something went wrong in the pager");
|
||||
throw new error("Something went wrong in the pager");
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
@ -411,12 +425,35 @@ int main(int argc, char * argv[], char * envp[])
|
|||
TRACE_POP(main, "Ledger done");
|
||||
return status;
|
||||
}
|
||||
catch (error * err) {
|
||||
std::cout.flush();
|
||||
// Push a null here since there's no file context
|
||||
if (err->context.empty() ||
|
||||
! dynamic_cast<xact_context *>(err->context.front()))
|
||||
err->context.push_front(new error_context(""));
|
||||
err->reveal_context(std::cerr, "Error");
|
||||
std::cerr << err->what() << std::endl;
|
||||
delete err;
|
||||
return 1;
|
||||
}
|
||||
catch (fatal * err) {
|
||||
std::cout.flush();
|
||||
// Push a null here since there's no file context
|
||||
if (err->context.empty() ||
|
||||
! dynamic_cast<xact_context *>(err->context.front()))
|
||||
err->context.push_front(new error_context(""));
|
||||
err->reveal_context(std::cerr, "Fatal");
|
||||
std::cerr << err->what() << std::endl;
|
||||
delete err;
|
||||
return 1;
|
||||
}
|
||||
catch (const std::exception& err) {
|
||||
std::cout.flush();
|
||||
std::cerr << "Error: " << err.what() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
catch (int& val) {
|
||||
return val; // this acts like a std::setjmp
|
||||
catch (int status) {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
3
mask.cc
3
mask.cc
|
|
@ -27,7 +27,8 @@ mask_t::mask_t(const std::string& pat) : exclude(false)
|
|||
regexp = pcre_compile(pattern.c_str(), PCRE_CASELESS,
|
||||
&error, &erroffset, NULL);
|
||||
if (! regexp)
|
||||
throw mask_error(std::string("Failed to compile regexp '") + pattern + "'");
|
||||
throw new mask_error(std::string("Failed to compile regexp '") +
|
||||
pattern + "'");
|
||||
}
|
||||
|
||||
mask_t::mask_t(const mask_t& m) : exclude(m.exclude), pattern(m.pattern)
|
||||
|
|
|
|||
11
mask.h
11
mask.h
|
|
@ -4,6 +4,8 @@
|
|||
#include <string>
|
||||
#include <exception>
|
||||
|
||||
#include "error.h"
|
||||
|
||||
class mask_t
|
||||
{
|
||||
public:
|
||||
|
|
@ -18,15 +20,10 @@ class mask_t
|
|||
bool match(const std::string& str) const;
|
||||
};
|
||||
|
||||
class mask_error : public std::exception {
|
||||
std::string reason;
|
||||
class mask_error : public error {
|
||||
public:
|
||||
mask_error(const std::string& _reason) throw() : reason(_reason) {}
|
||||
mask_error(const std::string& reason) throw() : error(reason) {}
|
||||
virtual ~mask_error() throw() {}
|
||||
|
||||
virtual const char* what() const throw() {
|
||||
return reason.c_str();
|
||||
}
|
||||
};
|
||||
|
||||
#endif // _MASK_H
|
||||
|
|
|
|||
43
option.cc
43
option.cc
|
|
@ -1,6 +1,7 @@
|
|||
#include "option.h"
|
||||
#include "config.h"
|
||||
#include "debug.h"
|
||||
#include "error.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <cstdarg>
|
||||
|
|
@ -10,7 +11,17 @@
|
|||
namespace {
|
||||
inline void process_option(option_t * opt, const char * arg = NULL) {
|
||||
if (! opt->handled) {
|
||||
opt->handler(arg);
|
||||
try {
|
||||
opt->handler(arg);
|
||||
}
|
||||
catch (error * err) {
|
||||
err->context.push_back
|
||||
(new error_context
|
||||
(std::string("While parsing option '--") + opt->long_opt +
|
||||
"'" + (opt->short_opt != '\0' ?
|
||||
(std::string(" (-") + opt->short_opt + "):") : ":")));
|
||||
throw err;
|
||||
}
|
||||
opt->handled = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -49,9 +60,8 @@ bool process_option(option_t * options, const std::string& name,
|
|||
const char * arg)
|
||||
{
|
||||
option_t * opt = search_options(options, name.c_str());
|
||||
if (opt && ! opt->handled) {
|
||||
opt->handler(arg);
|
||||
opt->handled = true;
|
||||
if (opt) {
|
||||
process_option(opt, arg);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
@ -90,25 +100,25 @@ void process_arguments(option_t * options, int argc, char ** argv,
|
|||
|
||||
opt = search_options(options, name);
|
||||
if (! opt)
|
||||
throw option_error(std::string("illegal option --") + name);
|
||||
throw new option_error(std::string("illegal option --") + name);
|
||||
|
||||
if (opt->wants_arg && ! value) {
|
||||
value = *++i;
|
||||
if (! value)
|
||||
throw option_error(std::string("missing option argument for --") +
|
||||
name);
|
||||
throw new option_error(std::string("missing option argument for --") +
|
||||
name);
|
||||
}
|
||||
process_option(opt, value);
|
||||
} else {
|
||||
char c = (*i)[1];
|
||||
opt = search_options(options, c);
|
||||
if (! opt)
|
||||
throw option_error(std::string("illegal option -") + c);
|
||||
throw new option_error(std::string("illegal option -") + c);
|
||||
|
||||
if (opt->wants_arg) {
|
||||
value = *++i;
|
||||
if (! value)
|
||||
throw option_error(std::string("missing option argument for -") + c);
|
||||
throw new option_error(std::string("missing option argument for -") + c);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -141,7 +151,18 @@ void process_environment(option_t * options, char ** envp,
|
|||
*r++ = std::tolower(*q);
|
||||
*r = '\0';
|
||||
|
||||
if (*q == '=')
|
||||
process_option(options, buf, q + 1);
|
||||
if (*q == '=') {
|
||||
try {
|
||||
process_option(options, buf, q + 1);
|
||||
}
|
||||
catch (error * err) {
|
||||
err->context.pop_back();
|
||||
err->context.push_back
|
||||
(new error_context
|
||||
(std::string("While parsing environment variable option '") +
|
||||
*p + "':"));
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
11
option.h
11
option.h
|
|
@ -5,6 +5,8 @@
|
|||
#include <string>
|
||||
#include <exception>
|
||||
|
||||
#include "error.h"
|
||||
|
||||
typedef void (*handler_t)(const char * arg);
|
||||
|
||||
struct option_t {
|
||||
|
|
@ -15,15 +17,10 @@ struct option_t {
|
|||
bool handled;
|
||||
};
|
||||
|
||||
class option_error : public std::exception {
|
||||
std::string reason;
|
||||
class option_error : public error {
|
||||
public:
|
||||
option_error(const std::string& _reason) throw() : reason(_reason) {}
|
||||
option_error(const std::string& reason) throw() : error(reason) {}
|
||||
virtual ~option_error() throw() {}
|
||||
|
||||
virtual const char* what() const throw() {
|
||||
return reason.c_str();
|
||||
}
|
||||
};
|
||||
|
||||
bool process_option(option_t * options, const std::string& opt,
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ unsigned int parse_journal_file(const std::string& path,
|
|||
journal->sources.push_back(path);
|
||||
|
||||
if (access(path.c_str(), R_OK) == -1)
|
||||
throw error(std::string("Cannot read file '") + path + "'");
|
||||
throw new error(std::string("Cannot read file '") + path + "'");
|
||||
|
||||
if (! original_file)
|
||||
original_file = &path;
|
||||
|
|
@ -119,8 +119,8 @@ unsigned int parse_ledger_data(config_t& config,
|
|||
if (parse_journal_file(config.init_file, config, journal) ||
|
||||
journal->auto_entries.size() > 0 ||
|
||||
journal->period_entries.size() > 0)
|
||||
throw error(std::string("Entries found in initialization file '") +
|
||||
config.init_file + "'");
|
||||
throw new error(std::string("Entries found in initialization file '") +
|
||||
config.init_file + "'");
|
||||
|
||||
journal->sources.pop_front(); // remove init file
|
||||
}
|
||||
|
|
@ -154,7 +154,7 @@ unsigned int parse_ledger_data(config_t& config,
|
|||
if (! journal->price_db.empty() &&
|
||||
access(journal->price_db.c_str(), R_OK) != -1) {
|
||||
if (parse_journal_file(journal->price_db, config, journal)) {
|
||||
throw error("Entries not allowed in price history file");
|
||||
throw new error("Entries not allowed in price history file");
|
||||
} else {
|
||||
DEBUG_PRINT("ledger.config.cache",
|
||||
"read price database " << journal->price_db);
|
||||
|
|
|
|||
9
qif.cc
9
qif.cc
|
|
@ -80,7 +80,7 @@ unsigned int qif_parser_t::parse(std::istream& in,
|
|||
case '\t':
|
||||
if (peek_next_nonws(in) != '\n') {
|
||||
get_line(in);
|
||||
throw parse_error(path, linenum, "Line begins with whitespace");
|
||||
throw new parse_error("Line begins with whitespace");
|
||||
}
|
||||
// fall through...
|
||||
|
||||
|
|
@ -97,16 +97,15 @@ unsigned int qif_parser_t::parse(std::istream& in,
|
|||
std::strcmp(line, "Type:Cat") == 0 ||
|
||||
std::strcmp(line, "Type:Class") == 0 ||
|
||||
std::strcmp(line, "Type:Memorized") == 0)
|
||||
throw parse_error(path, linenum,
|
||||
std::string("QIF files of type ") + line +
|
||||
" are not supported.");
|
||||
throw new parse_error(std::string("QIF files of type ") + line +
|
||||
" are not supported.");
|
||||
break;
|
||||
|
||||
case 'D':
|
||||
SET_BEG_POS_AND_LINE();
|
||||
get_line(in);
|
||||
if (! parse_date(line, &entry->_date))
|
||||
throw parse_error(path, linenum, "Failed to parse date");
|
||||
throw new parse_error("Failed to parse date");
|
||||
break;
|
||||
|
||||
case 'T':
|
||||
|
|
|
|||
|
|
@ -75,9 +75,9 @@ void quotes_by_script::operator()(commodity_base_t& commodity,
|
|||
<< " " << price << endl;
|
||||
}
|
||||
} else {
|
||||
throw error(std::string("Failed to download price for '") +
|
||||
commodity.symbol + "' (command: \"getquote " +
|
||||
commodity.symbol + "\")");
|
||||
throw new error(std::string("Failed to download price for '") +
|
||||
commodity.symbol + "' (command: \"getquote " +
|
||||
commodity.symbol + "\")");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ void reconcile_transactions::flush()
|
|||
}
|
||||
|
||||
if (cleared_balance.type >= value_t::BALANCE)
|
||||
throw error("Cannot reconcile accounts with multiple commodities");
|
||||
throw new error("Cannot reconcile accounts with multiple commodities");
|
||||
|
||||
cleared_balance.cast(value_t::AMOUNT);
|
||||
balance.cast(value_t::AMOUNT);
|
||||
|
|
@ -70,8 +70,8 @@ void reconcile_transactions::flush()
|
|||
|
||||
balance -= cleared_balance;
|
||||
if (balance.type >= value_t::BALANCE)
|
||||
throw error(std::string("Reconcile balance is not of the same commodity ('") +
|
||||
b_comm.symbol() + "' != '" + cb_comm.symbol() + "')");
|
||||
throw new error(std::string("Reconcile balance is not of the same commodity ('") +
|
||||
b_comm.symbol() + "' != '" + cb_comm.symbol() + "')");
|
||||
|
||||
// If the amount to reconcile is the same as the pending balance,
|
||||
// then assume an exact match and return the results right away.
|
||||
|
|
@ -81,7 +81,7 @@ void reconcile_transactions::flush()
|
|||
search_for_balance(to_reconcile, &first, first)) {
|
||||
push_to_handler(first);
|
||||
} else {
|
||||
throw error("Could not reconcile account!");
|
||||
throw new error("Could not reconcile account!");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
24
test.py
24
test.py
|
|
@ -2,15 +2,21 @@
|
|||
|
||||
from amounts import *
|
||||
|
||||
amt_ncd = Amount("100")
|
||||
print amt_ncd
|
||||
amt_nc = Amount("100.00")
|
||||
print amt_nc
|
||||
amt = Amount("$100.00")
|
||||
print amt
|
||||
namt_ncd = Amount("-100")
|
||||
print namt_ncd
|
||||
namt_nc = Amount("-100.00")
|
||||
print namt_nc
|
||||
namt = Amount("$-100.00")
|
||||
print namt
|
||||
namt2 = Amount("-$100.00")
|
||||
print namt2
|
||||
|
||||
val = Value("$100.00")
|
||||
|
||||
print val
|
||||
|
||||
amt = Amount("$100.00")
|
||||
|
||||
print amt.commodity
|
||||
amt.commodity = amt.commodity
|
||||
print amt
|
||||
amt.commodity = NullCommodity
|
||||
print amt
|
||||
print amt.quantity
|
||||
|
|
|
|||
111
textual.cc
111
textual.cc
|
|
@ -69,6 +69,9 @@ transaction_t * parse_transaction(char * line, account_t * account,
|
|||
{
|
||||
std::istringstream in(line);
|
||||
|
||||
std::string err_desc;
|
||||
try {
|
||||
|
||||
// The account will be determined later...
|
||||
std::auto_ptr<transaction_t> xact(new transaction_t(NULL));
|
||||
if (entry)
|
||||
|
|
@ -107,7 +110,7 @@ transaction_t * parse_transaction(char * line, account_t * account,
|
|||
}
|
||||
|
||||
if (account_beg == account_end)
|
||||
throw parse_error(path, linenum, "No account was specified");
|
||||
throw new parse_error("No account was specified");
|
||||
|
||||
char * b = &line[account_beg];
|
||||
char * e = &line[account_end];
|
||||
|
|
@ -144,7 +147,13 @@ transaction_t * parse_transaction(char * line, account_t * account,
|
|||
if (p == ';')
|
||||
goto parse_note;
|
||||
if (p == '(') {
|
||||
xact->amount_expr = parse_value_expr(in)->acquire();
|
||||
try {
|
||||
xact->amount_expr = parse_value_expr(in)->acquire();
|
||||
}
|
||||
catch (error * err) {
|
||||
err_desc = "While parsing transaction amount's value expression:";
|
||||
throw err;
|
||||
}
|
||||
DEBUG_PRINT("ledger.textual.parse", "line " << linenum << ": " <<
|
||||
"Parsed an amount expression");
|
||||
#ifdef DEBUG_ENABLED
|
||||
|
|
@ -156,8 +165,7 @@ transaction_t * parse_transaction(char * line, account_t * account,
|
|||
}
|
||||
#endif
|
||||
if (! compute_amount(xact->amount_expr, xact->amount, xact.get()))
|
||||
throw parse_error(path, linenum,
|
||||
"Value expression for amount failed to compute");
|
||||
throw new parse_error("Value expression for amount failed to compute");
|
||||
DEBUG_PRINT("ledger.textual.parse", "line " << linenum << ": " <<
|
||||
"The computed amount is " << xact->amount);
|
||||
} else {
|
||||
|
|
@ -209,8 +217,7 @@ transaction_t * parse_transaction(char * line, account_t * account,
|
|||
|
||||
p = peek_next_nonws(in);
|
||||
if (p == '(')
|
||||
throw parse_error(path, linenum,
|
||||
"A transaction's cost may not be a value expression");
|
||||
throw new parse_error("A transaction's cost may not be a value expression");
|
||||
|
||||
xact->cost->parse(in, AMOUNT_PARSE_NO_MIGRATE);
|
||||
DEBUG_PRINT("ledger.textual.parse", "line " << linenum << ": " <<
|
||||
|
|
@ -272,18 +279,26 @@ transaction_t * parse_transaction(char * line, account_t * account,
|
|||
if (char * p = std::strchr(buf, '=')) {
|
||||
*p++ = '\0';
|
||||
if (! quick_parse_date(p, &xact->_date_eff))
|
||||
throw parse_error(path, linenum,
|
||||
"Failed to parse effective date");
|
||||
throw new parse_error("Failed to parse effective date");
|
||||
}
|
||||
|
||||
if (buf[0] && ! quick_parse_date(buf, &xact->_date))
|
||||
throw parse_error(path, linenum, "Failed to parse date");
|
||||
throw new parse_error("Failed to parse date");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
finished:
|
||||
return xact.release();
|
||||
|
||||
}
|
||||
catch (error * err) {
|
||||
err->context.push_back
|
||||
(new line_context(line, (long)in.tellg() - 1,
|
||||
! err_desc.empty() ?
|
||||
err_desc : "While parsing transaction:"));
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
bool parse_transactions(std::istream& in,
|
||||
|
|
@ -337,11 +352,11 @@ entry_t * parse_entry(std::istream& in, char * line, account_t * master,
|
|||
if (char * p = std::strchr(line, '=')) {
|
||||
*p++ = '\0';
|
||||
if (! quick_parse_date(p, &curr->_date_eff))
|
||||
throw parse_error(path, linenum, "Failed to parse effective date");
|
||||
throw new parse_error("Failed to parse effective date");
|
||||
}
|
||||
|
||||
if (! quick_parse_date(line, &curr->_date))
|
||||
throw parse_error(path, linenum, "Failed to parse date");
|
||||
throw new parse_error("Failed to parse date");
|
||||
|
||||
TIMER_STOP(entry_date);
|
||||
|
||||
|
|
@ -436,8 +451,7 @@ static inline void parse_symbol(char *& p, std::string& symbol)
|
|||
if (*p == '"') {
|
||||
char * q = std::strchr(p + 1, '"');
|
||||
if (! q)
|
||||
throw parse_error(path, linenum,
|
||||
"Quoted commodity symbol lacks closing quote");
|
||||
throw new parse_error("Quoted commodity symbol lacks closing quote");
|
||||
symbol = std::string(p + 1, 0, q - p - 1);
|
||||
p = q + 2;
|
||||
} else {
|
||||
|
|
@ -449,7 +463,7 @@ static inline void parse_symbol(char *& p, std::string& symbol)
|
|||
p += symbol.length();
|
||||
}
|
||||
if (symbol.empty())
|
||||
throw parse_error(path, linenum, "Failed to parse commodity");
|
||||
throw new parse_error("Failed to parse commodity");
|
||||
}
|
||||
|
||||
bool textual_parser_t::test(std::istream& in) const
|
||||
|
|
@ -459,9 +473,9 @@ bool textual_parser_t::test(std::istream& in) const
|
|||
in.read(buf, 5);
|
||||
if (std::strncmp(buf, "<?xml", 5) == 0) {
|
||||
#if defined(HAVE_EXPAT) || defined(HAVE_XMLPARSE)
|
||||
throw parse_error(path, linenum, "Ledger file contains XML data, but format was not recognized");
|
||||
throw new parse_error("Ledger file contains XML data, but format was not recognized");
|
||||
#else
|
||||
throw parse_error(path, linenum, "Ledger file contains XML data, but no XML support present");
|
||||
throw new parse_error("Ledger file contains XML data, but no XML support present");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
@ -491,12 +505,13 @@ static void clock_out_from_timelog(const std::time_t when,
|
|||
curr->add_transaction(xact);
|
||||
|
||||
if (! journal->add_entry(curr.get()))
|
||||
throw parse_error(path, linenum,
|
||||
"Failed to record 'out' timelog entry");
|
||||
throw new parse_error("Failed to record 'out' timelog entry");
|
||||
else
|
||||
curr.release();
|
||||
}
|
||||
|
||||
static std::list<std::pair<std::string, int> > include_stack;
|
||||
|
||||
unsigned int textual_parser_t::parse(std::istream& in,
|
||||
config_t& config,
|
||||
journal_t * journal,
|
||||
|
|
@ -544,7 +559,7 @@ unsigned int textual_parser_t::parse(std::istream& in,
|
|||
case '\t': {
|
||||
char * p = skip_ws(line);
|
||||
if (*p && *p != '\r')
|
||||
throw parse_error(path, linenum - 1, "Line begins with whitespace");
|
||||
throw new parse_error("Line begins with whitespace");
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -563,7 +578,7 @@ unsigned int textual_parser_t::parse(std::istream& in,
|
|||
last_account = account_stack.front()->find_account(p);
|
||||
} else {
|
||||
last_account = NULL;
|
||||
throw parse_error(path, linenum, "Cannot parse timelog entry date");
|
||||
throw new parse_error("Cannot parse timelog entry date");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
@ -582,7 +597,7 @@ unsigned int textual_parser_t::parse(std::istream& in,
|
|||
clock_out_from_timelog(std::mktime(&when), journal);
|
||||
count++;
|
||||
} else {
|
||||
throw parse_error(path, linenum, "Cannot parse timelog entry date");
|
||||
throw new parse_error("Cannot parse timelog entry date");
|
||||
}
|
||||
|
||||
last_account = NULL;
|
||||
|
|
@ -625,7 +640,7 @@ unsigned int textual_parser_t::parse(std::istream& in,
|
|||
if (strptime(date_buffer, "%Y/%m/%d %H:%M:%S", &when)) {
|
||||
date = std::mktime(&when);
|
||||
} else {
|
||||
throw parse_error(path, linenum, "Failed to parse date");
|
||||
throw new parse_error("Failed to parse date");
|
||||
}
|
||||
|
||||
std::string symbol;
|
||||
|
|
@ -691,8 +706,7 @@ unsigned int textual_parser_t::parse(std::istream& in,
|
|||
case '~': { // period entry
|
||||
period_entry_t * pe = new period_entry_t(skip_ws(line + 1));
|
||||
if (! pe->period)
|
||||
throw parse_error(path, linenum,
|
||||
std::string("Parsing time period '") + line + "'");
|
||||
throw new parse_error(std::string("Parsing time period '") + line + "'");
|
||||
|
||||
if (parse_transactions(in, account_stack.front(), *pe,
|
||||
"period", end_pos)) {
|
||||
|
|
@ -705,7 +719,7 @@ unsigned int textual_parser_t::parse(std::istream& in,
|
|||
pe->end_pos = end_pos;
|
||||
pe->end_line = linenum;
|
||||
} else {
|
||||
throw parse_error(path, linenum, "Period entry failed to balance");
|
||||
throw new parse_error("Period entry failed to balance");
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
@ -730,11 +744,14 @@ unsigned int textual_parser_t::parse(std::istream& in,
|
|||
if (pos != std::string::npos)
|
||||
path = std::string(save_path.prev, 0, pos + 1) + path;
|
||||
}
|
||||
|
||||
DEBUG_PRINT("ledger.textual.include", "line " << linenum << ": " <<
|
||||
"Including path '" << path << "'");
|
||||
|
||||
include_stack.push_back(std::pair<std::string, int>
|
||||
(journal->sources.back(), linenum - 1));
|
||||
count += parse_journal_file(path, config, journal,
|
||||
account_stack.front());
|
||||
include_stack.pop_back();
|
||||
}
|
||||
else if (word == "account") {
|
||||
account_t * acct;
|
||||
|
|
@ -784,34 +801,32 @@ unsigned int textual_parser_t::parse(std::istream& in,
|
|||
entry->end_line = linenum;
|
||||
count++;
|
||||
} else {
|
||||
print_entry(std::cerr, *entry);
|
||||
delete entry;
|
||||
|
||||
std::ostringstream errmsg;
|
||||
errmsg << "Entry above does not balance; remainder is: "
|
||||
<< entry_balance;
|
||||
throw parse_error(path, first_line, errmsg.str());
|
||||
throw new parse_error("Entry does not balance");
|
||||
}
|
||||
} else {
|
||||
throw parse_error(path, first_line, "Failed to parse entry");
|
||||
throw new parse_error("Failed to parse entry");
|
||||
}
|
||||
end_pos = pos;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (const parse_error& err) {
|
||||
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;;
|
||||
catch (error * err) {
|
||||
for (std::list<std::pair<std::string, int> >::reverse_iterator i =
|
||||
include_stack.rbegin();
|
||||
i != include_stack.rend();
|
||||
i++)
|
||||
err->context.push_back(new include_context((*i).first, (*i).second,
|
||||
"In file included from"));
|
||||
err->context.push_front(new file_context(path, linenum - 1));
|
||||
|
||||
std::cout.flush();
|
||||
if (errors > 0)
|
||||
std::cerr << std::endl;
|
||||
err->reveal_context(std::cerr, "Error");
|
||||
std::cerr << err->what() << std::endl;
|
||||
delete err;
|
||||
errors++;
|
||||
}
|
||||
beg_pos = end_pos;
|
||||
|
|
@ -827,7 +842,7 @@ unsigned int textual_parser_t::parse(std::istream& in,
|
|||
journal->remove_entry_finalizer(&auto_entry_finalizer);
|
||||
|
||||
if (errors > 0)
|
||||
throw error(std::string("Errors parsing file '") + path + "'");
|
||||
throw (int)errors;
|
||||
|
||||
TIMER_STOP(parsing_total);
|
||||
|
||||
|
|
@ -869,8 +884,8 @@ void write_textual_journal(journal_t& journal, std::string path,
|
|||
#endif
|
||||
|
||||
if (found.empty())
|
||||
throw error(std::string("Journal does not refer to file '") +
|
||||
path + "'");
|
||||
throw new error(std::string("Journal does not refer to file '") +
|
||||
path + "'");
|
||||
|
||||
entries_list::iterator el = journal.entries.begin();
|
||||
auto_entries_list::iterator al = journal.auto_entries.begin();
|
||||
|
|
|
|||
329
valexpr.cc
329
valexpr.cc
|
|
@ -7,8 +7,8 @@
|
|||
|
||||
namespace ledger {
|
||||
|
||||
std::auto_ptr<value_calc> amount_expr;
|
||||
std::auto_ptr<value_calc> total_expr;
|
||||
std::auto_ptr<value_expr> amount_expr;
|
||||
std::auto_ptr<value_expr> total_expr;
|
||||
|
||||
std::auto_ptr<scope_t> global_scope;
|
||||
std::time_t terminus;
|
||||
|
|
@ -23,22 +23,21 @@ bool compute_amount(value_expr_t * expr, amount_t& amt,
|
|||
const transaction_t * xact, value_expr_t * context)
|
||||
{
|
||||
value_t result;
|
||||
expr->compute(result, xact ? details_t(*xact) : details_t(), context);
|
||||
switch (result.type) {
|
||||
case value_t::BOOLEAN:
|
||||
amt = *((bool *) result.data);
|
||||
break;
|
||||
case value_t::INTEGER:
|
||||
amt = *((long *) result.data);
|
||||
break;
|
||||
case value_t::AMOUNT:
|
||||
try {
|
||||
expr->compute(result, xact ? details_t(*xact) : details_t(), context);
|
||||
result.cast(value_t::AMOUNT);
|
||||
amt = *((amount_t *) result.data);
|
||||
break;
|
||||
|
||||
case value_t::DATETIME:
|
||||
case value_t::BALANCE:
|
||||
case value_t::BALANCE_PAIR:
|
||||
return false;
|
||||
}
|
||||
catch (error * err) {
|
||||
if (err->context.empty() ||
|
||||
! dynamic_cast<valexpr_context *>(err->context.back()))
|
||||
err->context.push_back(new valexpr_context(expr));
|
||||
error_context * last = err->context.back();
|
||||
if (valexpr_context * ctxt = dynamic_cast<valexpr_context *>(last)) {
|
||||
ctxt->expr = expr->acquire();
|
||||
ctxt->desc = "While computing amount expression:";
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
@ -145,6 +144,7 @@ namespace {
|
|||
void value_expr_t::compute(value_t& result, const details_t& details,
|
||||
value_expr_t * context) const
|
||||
{
|
||||
try {
|
||||
switch (kind) {
|
||||
case CONSTANT_I:
|
||||
result = constant_i;
|
||||
|
|
@ -385,7 +385,8 @@ void value_expr_t::compute(value_t& result, const details_t& details,
|
|||
moment.cast(value_t::INTEGER);
|
||||
result -= moment;
|
||||
} else {
|
||||
throw compute_error("Invalid date passed to datecmp(value,date)");
|
||||
throw new compute_error("Invalid date passed to datecmp(value,date)",
|
||||
new valexpr_context(expr));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
@ -459,7 +460,8 @@ void value_expr_t::compute(value_t& result, const details_t& details,
|
|||
value_expr_t * expr = find_leaf(context, 0, index);
|
||||
expr->compute(result, details, context);
|
||||
if (result.type != value_t::AMOUNT)
|
||||
throw compute_error("Argument to commodity() must be a commoditized amount");
|
||||
throw new compute_error("Argument to commodity() must be a commoditized amount",
|
||||
new valexpr_context(expr));
|
||||
amount_t temp("1");
|
||||
temp.set_commodity(((amount_t *) result.data)->commodity());
|
||||
result = temp;
|
||||
|
|
@ -476,7 +478,8 @@ void value_expr_t::compute(value_t& result, const details_t& details,
|
|||
expr = find_leaf(context, 1, index);
|
||||
expr->compute(result, details, context);
|
||||
if (result.type != value_t::AMOUNT)
|
||||
throw compute_error("Second argument to set_commodity() must be a commoditized amount");
|
||||
throw new compute_error("Second argument to set_commodity() must be a commoditized amount",
|
||||
new valexpr_context(expr));
|
||||
amount_t one("1");
|
||||
one.set_commodity(((amount_t *) result.data)->commodity());
|
||||
result = one;
|
||||
|
|
@ -594,7 +597,7 @@ void value_expr_t::compute(value_t& result, const details_t& details,
|
|||
break;
|
||||
|
||||
case O_DEF:
|
||||
throw compute_error("Cannot compute function definition");
|
||||
throw new compute_error("Cannot compute function definition");
|
||||
|
||||
case O_REF: {
|
||||
assert(left);
|
||||
|
|
@ -617,7 +620,8 @@ void value_expr_t::compute(value_t& result, const details_t& details,
|
|||
value_t moment;
|
||||
expr->compute(moment, details, context);
|
||||
if (moment.type != value_t::DATETIME)
|
||||
throw compute_error("Invalid date passed to P(value,date)");
|
||||
throw new compute_error("Invalid date passed to P(value,date)",
|
||||
new valexpr_context(expr));
|
||||
|
||||
result = result.value(*((datetime_t *)moment.data));
|
||||
break;
|
||||
|
|
@ -718,20 +722,27 @@ void value_expr_t::compute(value_t& result, const details_t& details,
|
|||
assert(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (error * err) {
|
||||
if (err->context.empty() ||
|
||||
! dynamic_cast<valexpr_context *>(err->context.back()))
|
||||
err->context.push_back(new valexpr_context(this));
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void unexpected(char c, char wanted = '\0') {
|
||||
if ((unsigned char) c == 0xff) {
|
||||
if (wanted)
|
||||
throw value_expr_error(std::string("Missing '") + wanted + "'");
|
||||
throw new value_expr_error(std::string("Missing '") + wanted + "'");
|
||||
else
|
||||
throw value_expr_error("Unexpected end");
|
||||
throw new value_expr_error("Unexpected end");
|
||||
} else {
|
||||
if (wanted)
|
||||
throw value_expr_error(std::string("Invalid char '") + c +
|
||||
throw new value_expr_error(std::string("Invalid char '") + c +
|
||||
"' (wanted '" + wanted + "')");
|
||||
else
|
||||
throw value_expr_error(std::string("Invalid char '") + c + "'");
|
||||
throw new value_expr_error(std::string("Invalid char '") + c + "'");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -838,7 +849,7 @@ value_expr_t * parse_value_term(std::istream& in, scope_t * scope)
|
|||
// Define the value associated with the defined identifier
|
||||
value_auto_ptr def(parse_boolean_expr(in, params.get()));
|
||||
if (! def.get())
|
||||
throw value_expr_error(std::string("Definition failed for '") + buf + "'");
|
||||
throw new value_expr_error(std::string("Definition failed for '") + buf + "'");
|
||||
|
||||
node.reset(new value_expr_t(value_expr_t::O_DEF));
|
||||
node->set_left(new value_expr_t(value_expr_t::CONSTANT_I));
|
||||
|
|
@ -858,7 +869,7 @@ value_expr_t * parse_value_term(std::istream& in, scope_t * scope)
|
|||
(buf[0] == 'c' || buf[0] == 'C' || buf[0] == 'p' ||
|
||||
buf[0] == 'w' || buf[0] == 'W' || buf[0] == 'e'))
|
||||
goto find_term;
|
||||
throw value_expr_error(std::string("Unknown identifier '") + buf + "'");
|
||||
throw new value_expr_error(std::string("Unknown identifier '") + buf + "'");
|
||||
}
|
||||
else if (def->kind == value_expr_t::O_DEF) {
|
||||
node.reset(new value_expr_t(value_expr_t::O_REF));
|
||||
|
|
@ -887,7 +898,7 @@ value_expr_t * parse_value_term(std::istream& in, scope_t * scope)
|
|||
errmsg << "Wrong number of arguments to '" << buf
|
||||
<< "': saw " << count
|
||||
<< ", wanted " << def->left->constant_i;
|
||||
throw value_expr_error(errmsg.str());
|
||||
throw new value_expr_error(errmsg.str());
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
|
@ -1467,7 +1478,7 @@ value_expr_t * parse_value_expr(std::istream& in, scope_t * scope,
|
|||
if (! node.get()) {
|
||||
in.get(c);
|
||||
if (in.eof())
|
||||
throw value_expr_error(std::string("Failed to parse value expression"));
|
||||
throw new value_expr_error(std::string("Failed to parse value expression"));
|
||||
else
|
||||
unexpected(c);
|
||||
} else if (! partial) {
|
||||
|
|
@ -1481,6 +1492,264 @@ value_expr_t * parse_value_expr(std::istream& in, scope_t * scope,
|
|||
return node.release();
|
||||
}
|
||||
|
||||
unsigned long write_value_expr(std::ostream& out,
|
||||
const value_expr_t * node,
|
||||
const value_expr_t * node_to_find,
|
||||
unsigned long start_pos)
|
||||
{
|
||||
long pos = start_pos;
|
||||
|
||||
switch (node->kind) {
|
||||
case value_expr_t::CONSTANT_I:
|
||||
out << node->constant_i;
|
||||
break;
|
||||
case value_expr_t::CONSTANT_T:
|
||||
out << "[" << *(node->constant_t) << ']';
|
||||
break;
|
||||
case value_expr_t::CONSTANT_A:
|
||||
out << "{" << *(node->constant_a) << '}';
|
||||
break;
|
||||
case value_expr_t::CONSTANT_V:
|
||||
out << "{" << *(node->constant_v) << '}';
|
||||
break;
|
||||
|
||||
case value_expr_t::AMOUNT: out << "amount"; break;
|
||||
case value_expr_t::PRICE: out << "price"; break;
|
||||
case value_expr_t::COST: out << "cost"; break;
|
||||
case value_expr_t::DATE: out << "date"; break;
|
||||
case value_expr_t::ACT_DATE: out << "actual_date"; break;
|
||||
case value_expr_t::EFF_DATE: out << "effective_date"; break;
|
||||
case value_expr_t::CLEARED: out << "cleared"; break;
|
||||
case value_expr_t::PENDING: out << "pending"; break;
|
||||
case value_expr_t::REAL: out << "real"; break;
|
||||
case value_expr_t::ACTUAL: out << "actual"; break;
|
||||
case value_expr_t::INDEX: out << "index"; break;
|
||||
case value_expr_t::COUNT: out << "count"; break;
|
||||
case value_expr_t::DEPTH: out << "depth"; break;
|
||||
case value_expr_t::TOTAL: out << "total"; break;
|
||||
case value_expr_t::PRICE_TOTAL: out << "total_price"; break;
|
||||
case value_expr_t::COST_TOTAL: out << "total_cost"; break;
|
||||
case value_expr_t::F_NOW: out << "now"; break;
|
||||
|
||||
case value_expr_t::F_ARITH_MEAN:
|
||||
out << "average(";
|
||||
pos = write_value_expr(out, node->left, node_to_find, pos);
|
||||
out << ")";
|
||||
break;
|
||||
case value_expr_t::F_ABS: out << "abs"; break;
|
||||
out << "abs(";
|
||||
pos = write_value_expr(out, node->left, node_to_find, pos);
|
||||
out << ")";
|
||||
break;
|
||||
case value_expr_t::F_QUANTITY: out << "quantity"; break;
|
||||
out << "quantity(";
|
||||
pos = write_value_expr(out, node->left, node_to_find, pos);
|
||||
out << ")";
|
||||
break;
|
||||
case value_expr_t::F_COMMODITY: out << "commodity"; break;
|
||||
out << "commodity(";
|
||||
pos = write_value_expr(out, node->left, node_to_find, pos);
|
||||
out << ")";
|
||||
break;
|
||||
case value_expr_t::F_SET_COMMODITY: out << "set_commodity"; break;
|
||||
out << "average(";
|
||||
pos = write_value_expr(out, node->left, node_to_find, pos);
|
||||
out << ")";
|
||||
break;
|
||||
case value_expr_t::F_VALUE: out << "valueof"; break;
|
||||
out << "average(";
|
||||
pos = write_value_expr(out, node->left, node_to_find, pos);
|
||||
out << ")";
|
||||
break;
|
||||
case value_expr_t::F_PRICE: out << "priceof"; break;
|
||||
out << "average(";
|
||||
pos = write_value_expr(out, node->left, node_to_find, pos);
|
||||
out << ")";
|
||||
break;
|
||||
case value_expr_t::F_DATE: out << "dateof"; break;
|
||||
out << "average(";
|
||||
pos = write_value_expr(out, node->left, node_to_find, pos);
|
||||
out << ")";
|
||||
break;
|
||||
case value_expr_t::F_DATECMP: out << "datecmp"; break;
|
||||
out << "average(";
|
||||
pos = write_value_expr(out, node->left, node_to_find, pos);
|
||||
out << ")";
|
||||
break;
|
||||
case value_expr_t::F_YEAR: out << "yearof"; break;
|
||||
out << "average(";
|
||||
pos = write_value_expr(out, node->left, node_to_find, pos);
|
||||
out << ")";
|
||||
break;
|
||||
case value_expr_t::F_MONTH: out << "monthof"; break;
|
||||
out << "average(";
|
||||
pos = write_value_expr(out, node->left, node_to_find, pos);
|
||||
out << ")";
|
||||
break;
|
||||
case value_expr_t::F_DAY: out << "dayof"; break;
|
||||
out << "average(";
|
||||
pos = write_value_expr(out, node->left, node_to_find, pos);
|
||||
out << ")";
|
||||
break;
|
||||
|
||||
case value_expr_t::F_CODE_MASK:
|
||||
out << "c/" << node->mask->pattern << "/";
|
||||
break;
|
||||
case value_expr_t::F_PAYEE_MASK:
|
||||
out << "p/" << node->mask->pattern << "/";
|
||||
break;
|
||||
case value_expr_t::F_NOTE_MASK:
|
||||
out << "e/" << node->mask->pattern << "/";
|
||||
break;
|
||||
case value_expr_t::F_ACCOUNT_MASK:
|
||||
out << "W/" << node->mask->pattern << "/";
|
||||
break;
|
||||
case value_expr_t::F_SHORT_ACCOUNT_MASK:
|
||||
out << "w/" << node->mask->pattern << "/";
|
||||
break;
|
||||
case value_expr_t::F_COMMODITY_MASK:
|
||||
out << "C/" << node->mask->pattern << "/";
|
||||
break;
|
||||
|
||||
case value_expr_t::O_NOT:
|
||||
out << "!";
|
||||
pos = write_value_expr(out, node->left, node_to_find, pos);
|
||||
break;
|
||||
case value_expr_t::O_NEG:
|
||||
out << "-";
|
||||
pos = write_value_expr(out, node->left, node_to_find, pos);
|
||||
break;
|
||||
case value_expr_t::O_PERC:
|
||||
out << "%";
|
||||
pos = write_value_expr(out, node->left, node_to_find, pos);
|
||||
break;
|
||||
|
||||
case value_expr_t::O_ARG:
|
||||
out << "arg" << node->constant_i;
|
||||
break;
|
||||
case value_expr_t::O_DEF:
|
||||
out << "O_DEF";
|
||||
break;
|
||||
case value_expr_t::O_REF:
|
||||
break;
|
||||
|
||||
case value_expr_t::O_COM:
|
||||
pos = write_value_expr(out, node->left, node_to_find, pos);
|
||||
out << ", ";
|
||||
pos = write_value_expr(out, node->right, node_to_find, pos);
|
||||
break;
|
||||
case value_expr_t::O_QUES:
|
||||
out << "(";
|
||||
pos = write_value_expr(out, node->left, node_to_find, pos);
|
||||
out << " ? ";
|
||||
pos = write_value_expr(out, node->right, node_to_find, pos);
|
||||
out << ")";
|
||||
break;
|
||||
case value_expr_t::O_COL:
|
||||
pos = write_value_expr(out, node->left, node_to_find, pos);
|
||||
out << " : ";
|
||||
pos = write_value_expr(out, node->right, node_to_find, pos);
|
||||
break;
|
||||
|
||||
case value_expr_t::O_AND: out << "O_AND"; break;
|
||||
out << "(";
|
||||
pos = write_value_expr(out, node->left, node_to_find, pos);
|
||||
out << " & ";
|
||||
pos = write_value_expr(out, node->right, node_to_find, pos);
|
||||
out << ")";
|
||||
break;
|
||||
case value_expr_t::O_OR: out << "O_OR"; break;
|
||||
out << "(";
|
||||
pos = write_value_expr(out, node->left, node_to_find, pos);
|
||||
out << " | ";
|
||||
pos = write_value_expr(out, node->right, node_to_find, pos);
|
||||
out << ")";
|
||||
break;
|
||||
|
||||
case value_expr_t::O_NEQ:
|
||||
out << "(";
|
||||
pos = write_value_expr(out, node->left, node_to_find, pos);
|
||||
out << " != ";
|
||||
pos = write_value_expr(out, node->right, node_to_find, pos);
|
||||
out << ")";
|
||||
break;
|
||||
case value_expr_t::O_EQ:
|
||||
out << "(";
|
||||
pos = write_value_expr(out, node->left, node_to_find, pos);
|
||||
out << " == ";
|
||||
pos = write_value_expr(out, node->right, node_to_find, pos);
|
||||
out << ")";
|
||||
break;
|
||||
case value_expr_t::O_LT:
|
||||
out << "(";
|
||||
pos = write_value_expr(out, node->left, node_to_find, pos);
|
||||
out << " < ";
|
||||
pos = write_value_expr(out, node->right, node_to_find, pos);
|
||||
out << ")";
|
||||
break;
|
||||
case value_expr_t::O_LTE:
|
||||
out << "(";
|
||||
pos = write_value_expr(out, node->left, node_to_find, pos);
|
||||
out << " <= ";
|
||||
pos = write_value_expr(out, node->right, node_to_find, pos);
|
||||
out << ")";
|
||||
break;
|
||||
case value_expr_t::O_GT:
|
||||
out << "(";
|
||||
pos = write_value_expr(out, node->left, node_to_find, pos);
|
||||
out << " > ";
|
||||
pos = write_value_expr(out, node->right, node_to_find, pos);
|
||||
out << ")";
|
||||
break;
|
||||
case value_expr_t::O_GTE:
|
||||
out << "(";
|
||||
pos = write_value_expr(out, node->left, node_to_find, pos);
|
||||
out << " >= ";
|
||||
pos = write_value_expr(out, node->right, node_to_find, pos);
|
||||
out << ")";
|
||||
break;
|
||||
|
||||
case value_expr_t::O_ADD:
|
||||
out << "(";
|
||||
pos = write_value_expr(out, node->left, node_to_find, pos);
|
||||
out << " + ";
|
||||
pos = write_value_expr(out, node->right, node_to_find, pos);
|
||||
out << ")";
|
||||
break;
|
||||
case value_expr_t::O_SUB:
|
||||
out << "(";
|
||||
pos = write_value_expr(out, node->left, node_to_find, pos);
|
||||
out << " - ";
|
||||
pos = write_value_expr(out, node->right, node_to_find, pos);
|
||||
out << ")";
|
||||
break;
|
||||
case value_expr_t::O_MUL:
|
||||
out << "(";
|
||||
pos = write_value_expr(out, node->left, node_to_find, pos);
|
||||
out << " * ";
|
||||
pos = write_value_expr(out, node->right, node_to_find, pos);
|
||||
out << ")";
|
||||
break;
|
||||
case value_expr_t::O_DIV:
|
||||
out << "(";
|
||||
pos = write_value_expr(out, node->left, node_to_find, pos);
|
||||
out << " / ";
|
||||
pos = write_value_expr(out, node->right, node_to_find, pos);
|
||||
out << ")";
|
||||
break;
|
||||
|
||||
case value_expr_t::LAST:
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
|
||||
if (node == node_to_find)
|
||||
pos = (long)out.tellp() - 1;
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
void dump_value_expr(std::ostream& out, const value_expr_t * node,
|
||||
const int depth)
|
||||
{
|
||||
|
|
|
|||
164
valexpr.h
164
valexpr.h
|
|
@ -33,39 +33,6 @@ struct details_t
|
|||
#endif
|
||||
};
|
||||
|
||||
class value_calc
|
||||
{
|
||||
public:
|
||||
virtual ~value_calc() {}
|
||||
virtual void compute(value_t& result,
|
||||
const details_t& details = details_t(),
|
||||
value_expr_t * context = NULL) = 0;
|
||||
virtual value_t compute(const details_t& details = details_t(),
|
||||
value_expr_t * context = NULL) = 0;
|
||||
};
|
||||
|
||||
typedef void (*value_func_t)(value_t& result, const details_t& details,
|
||||
value_expr_t * context);
|
||||
|
||||
class value_func : public value_calc
|
||||
{
|
||||
value_func_t func;
|
||||
public:
|
||||
value_func(value_func_t _func) : func(_func) {}
|
||||
|
||||
virtual void compute(value_t& result,
|
||||
const details_t& details = details_t(),
|
||||
value_expr_t * context = NULL) {
|
||||
func(result, details, context);
|
||||
}
|
||||
virtual value_t compute(const details_t& details = details_t(),
|
||||
value_expr_t * context = NULL) {
|
||||
value_t temp;
|
||||
func(temp, details, context);
|
||||
return temp;
|
||||
}
|
||||
};
|
||||
|
||||
struct value_expr_t
|
||||
{
|
||||
enum kind_t {
|
||||
|
|
@ -252,8 +219,8 @@ struct scope_t
|
|||
= symbols.insert(symbol_pair(name, def));
|
||||
if (! result.second) {
|
||||
def->release();
|
||||
throw value_expr_error(std::string("Redefinition of '") +
|
||||
name + "' in same scope");
|
||||
throw new compute_error(std::string("Redefinition of '") +
|
||||
name + "' in same scope");
|
||||
}
|
||||
}
|
||||
def->acquire();
|
||||
|
|
@ -282,37 +249,87 @@ bool compute_amount(value_expr_t * expr, amount_t& amt,
|
|||
struct scope_t;
|
||||
value_expr_t * parse_boolean_expr(std::istream& in, scope_t * scope);
|
||||
|
||||
inline value_expr_t * parse_boolean_expr(const char * p,
|
||||
scope_t * scope = NULL) {
|
||||
std::istringstream stream(p);
|
||||
return parse_boolean_expr(stream, scope);
|
||||
}
|
||||
|
||||
inline value_expr_t * parse_boolean_expr(const std::string& str,
|
||||
scope_t * scope = NULL) {
|
||||
return parse_boolean_expr(str.c_str(), scope);
|
||||
std::istringstream stream(str);
|
||||
try {
|
||||
return parse_boolean_expr(stream, scope);
|
||||
}
|
||||
catch (error * err) {
|
||||
err->context.push_back
|
||||
(new error_context("While parsing value expression: " + str));
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
inline value_expr_t * parse_boolean_expr(const char * p,
|
||||
scope_t * scope = NULL) {
|
||||
return parse_boolean_expr(std::string(p), scope);
|
||||
}
|
||||
|
||||
value_expr_t * parse_value_expr(std::istream& in,
|
||||
scope_t * scope = NULL,
|
||||
const bool partial = false);
|
||||
|
||||
inline value_expr_t * parse_value_expr(const char * p,
|
||||
scope_t * scope = NULL,
|
||||
const bool partial = false) {
|
||||
std::istringstream stream(p);
|
||||
return parse_value_expr(stream, scope, partial);
|
||||
}
|
||||
|
||||
inline value_expr_t * parse_value_expr(const std::string& str,
|
||||
scope_t * scope = NULL,
|
||||
const bool partial = false) {
|
||||
return parse_value_expr(str.c_str(), scope);
|
||||
std::istringstream stream(str);
|
||||
try {
|
||||
return parse_value_expr(stream, scope, partial);
|
||||
}
|
||||
catch (error * err) {
|
||||
err->context.push_back
|
||||
(new line_context(str, (long)stream.tellg() - 1,
|
||||
"While parsing value expression:"));
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
inline value_expr_t * parse_value_expr(const char * p,
|
||||
scope_t * scope = NULL,
|
||||
const bool partial = false) {
|
||||
return parse_value_expr(std::string(p), scope, partial);
|
||||
}
|
||||
|
||||
void dump_value_expr(std::ostream& out, const value_expr_t * node,
|
||||
const int depth = 0);
|
||||
|
||||
unsigned long write_value_expr(std::ostream& out,
|
||||
const value_expr_t * node,
|
||||
const value_expr_t * node_to_find = NULL,
|
||||
unsigned long start_pos = 0UL);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline void guarded_compute(const value_expr_t * expr,
|
||||
value_t& result,
|
||||
const details_t& details = details_t(),
|
||||
value_expr_t * context = NULL) {
|
||||
try {
|
||||
expr->compute(result, details);
|
||||
}
|
||||
catch (error * err) {
|
||||
if (err->context.empty() ||
|
||||
! dynamic_cast<valexpr_context *>(err->context.back()))
|
||||
err->context.push_back(new valexpr_context(expr));
|
||||
error_context * last = err->context.back();
|
||||
if (valexpr_context * ctxt = dynamic_cast<valexpr_context *>(last)) {
|
||||
ctxt->expr = expr->acquire();
|
||||
ctxt->desc = "While computing value expression:";
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
inline value_t guarded_compute(const value_expr_t * expr,
|
||||
const details_t& details = details_t(),
|
||||
value_expr_t * context = NULL) {
|
||||
value_t temp;
|
||||
guarded_compute(expr, temp, details, context);
|
||||
return temp;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// This class is used so that during the "in between" stages of value
|
||||
|
|
@ -323,10 +340,11 @@ void dump_value_expr(std::ostream& out, const value_expr_t * node,
|
|||
struct value_auto_ptr {
|
||||
value_expr_t * ptr;
|
||||
value_auto_ptr() : ptr(NULL) {}
|
||||
explicit value_auto_ptr(value_expr_t * _ptr) : ptr(_ptr) {}
|
||||
explicit value_auto_ptr(value_expr_t * _ptr)
|
||||
: ptr(_ptr ? _ptr->acquire() : NULL) {}
|
||||
~value_auto_ptr() {
|
||||
if (ptr && ptr->refc == 0)
|
||||
delete ptr;
|
||||
if (ptr)
|
||||
ptr->release();
|
||||
}
|
||||
value_expr_t& operator*() const throw() {
|
||||
return *ptr;
|
||||
|
|
@ -342,31 +360,24 @@ struct value_auto_ptr {
|
|||
}
|
||||
void reset(value_expr_t * p = 0) throw() {
|
||||
if (p != ptr) {
|
||||
if (ptr && ptr->refc == 0)
|
||||
delete ptr;
|
||||
ptr = p;
|
||||
if (ptr)
|
||||
ptr->release();
|
||||
ptr = p->acquire();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
class value_expr : public value_calc
|
||||
class value_expr
|
||||
{
|
||||
std::string expr;
|
||||
value_expr_t * parsed;
|
||||
|
||||
public:
|
||||
std::string expr;
|
||||
|
||||
value_expr(const std::string& _expr) : expr(_expr) {
|
||||
DEBUG_PRINT("ledger.memory.ctors", "ctor value_expr");
|
||||
try {
|
||||
parsed = parse_value_expr(expr);
|
||||
parsed->acquire();
|
||||
}
|
||||
catch (const value_expr_error& err) {
|
||||
throw error(std::string("In value expression '") +
|
||||
expr + "': " + err.what());
|
||||
}
|
||||
parsed = parse_value_expr(expr)->acquire();
|
||||
}
|
||||
value_expr(value_expr_t * _parsed) : parsed(_parsed->acquire()) {
|
||||
DEBUG_PRINT("ledger.memory.ctors", "ctor value_expr");
|
||||
|
|
@ -380,18 +391,18 @@ public:
|
|||
virtual void compute(value_t& result,
|
||||
const details_t& details = details_t(),
|
||||
value_expr_t * context = NULL) {
|
||||
parsed->compute(result, details, context);
|
||||
guarded_compute(parsed, result, details, context);
|
||||
}
|
||||
virtual value_t compute(const details_t& details = details_t(),
|
||||
value_expr_t * context = NULL) {
|
||||
value_t temp;
|
||||
parsed->compute(temp, details, context);
|
||||
guarded_compute(parsed, temp, details, context);
|
||||
return temp;
|
||||
}
|
||||
};
|
||||
|
||||
extern std::auto_ptr<value_calc> amount_expr;
|
||||
extern std::auto_ptr<value_calc> total_expr;
|
||||
extern std::auto_ptr<value_expr> amount_expr;
|
||||
extern std::auto_ptr<value_expr> total_expr;
|
||||
|
||||
inline void compute_amount(value_t& result,
|
||||
const details_t& details = details_t()) {
|
||||
|
|
@ -425,15 +436,8 @@ class item_predicate
|
|||
|
||||
item_predicate(const std::string& _predicate) : predicate(NULL) {
|
||||
DEBUG_PRINT("ledger.memory.ctors", "ctor item_predicate<T>");
|
||||
if (! _predicate.empty()) {
|
||||
try {
|
||||
predicate = parse_value_expr(_predicate)->acquire();
|
||||
}
|
||||
catch (value_expr_error& err) {
|
||||
throw value_expr_error(std::string("In predicate '") +
|
||||
_predicate + "': " + err.what());
|
||||
}
|
||||
}
|
||||
if (! _predicate.empty())
|
||||
predicate = parse_value_expr(_predicate)->acquire();
|
||||
}
|
||||
item_predicate(const value_expr_t * _predicate = NULL)
|
||||
: predicate(_predicate->acquire()) {
|
||||
|
|
|
|||
179
value.cc
179
value.cc
|
|
@ -1,5 +1,6 @@
|
|||
#include "value.h"
|
||||
#include "debug.h"
|
||||
#include "error.h"
|
||||
|
||||
namespace ledger {
|
||||
|
||||
|
|
@ -93,13 +94,13 @@ value_t& value_t::operator=(const value_t& value)
|
|||
value_t& value_t::operator+=(const value_t& value)
|
||||
{
|
||||
if (value.type == BOOLEAN)
|
||||
throw value_error("Cannot add a boolean to a value");
|
||||
throw new value_error("Cannot add a boolean to a value");
|
||||
else if (value.type == DATETIME)
|
||||
throw value_error("Cannot add a date/time to a value");
|
||||
throw new value_error("Cannot add a date/time to a value");
|
||||
|
||||
switch (type) {
|
||||
case BOOLEAN:
|
||||
throw value_error("Cannot add a value to a boolean");
|
||||
throw new value_error("Cannot add a value to a boolean");
|
||||
|
||||
case INTEGER:
|
||||
switch (value.type) {
|
||||
|
|
@ -231,13 +232,13 @@ value_t& value_t::operator+=(const value_t& value)
|
|||
value_t& value_t::operator-=(const value_t& value)
|
||||
{
|
||||
if (value.type == BOOLEAN)
|
||||
throw value_error("Cannot subtract a boolean from a value");
|
||||
else if (value.type == DATETIME)
|
||||
throw value_error("Cannot subtract a date/time from a value");
|
||||
throw new value_error("Cannot subtract a boolean from a value");
|
||||
else if (value.type == DATETIME && type != DATETIME)
|
||||
throw new value_error("Cannot subtract a date/time from a value");
|
||||
|
||||
switch (type) {
|
||||
case BOOLEAN:
|
||||
throw value_error("Cannot subtract a value from a boolean");
|
||||
throw new value_error("Cannot subtract a value from a boolean");
|
||||
|
||||
case INTEGER:
|
||||
switch (value.type) {
|
||||
|
|
@ -262,6 +263,32 @@ value_t& value_t::operator-=(const value_t& value)
|
|||
}
|
||||
break;
|
||||
|
||||
case DATETIME:
|
||||
switch (value.type) {
|
||||
case INTEGER:
|
||||
*((datetime_t *) data) -= *((long *) value.data);
|
||||
break;
|
||||
case DATETIME: {
|
||||
long val = *((datetime_t *) data) - *((datetime_t *) value.data);
|
||||
cast(INTEGER);
|
||||
*((long *) data) = val;
|
||||
break;
|
||||
}
|
||||
case AMOUNT:
|
||||
*((datetime_t *) data) -= long(*((amount_t *) value.data));
|
||||
break;
|
||||
case BALANCE:
|
||||
*((datetime_t *) data) -= long(*((balance_t *) value.data));
|
||||
break;
|
||||
case BALANCE_PAIR:
|
||||
*((datetime_t *) data) -= long(*((balance_pair_t *) value.data));
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case AMOUNT:
|
||||
switch (value.type) {
|
||||
case INTEGER:
|
||||
|
|
@ -352,9 +379,9 @@ value_t& value_t::operator-=(const value_t& value)
|
|||
value_t& value_t::operator*=(const value_t& value)
|
||||
{
|
||||
if (value.type == BOOLEAN)
|
||||
throw value_error("Cannot multiply a boolean by a value");
|
||||
throw new value_error("Cannot multiply a boolean by a value");
|
||||
else if (value.type == DATETIME)
|
||||
throw value_error("Cannot multiply a date/time by a value");
|
||||
throw new value_error("Cannot multiply a date/time by a value");
|
||||
|
||||
if (value.realzero()) {
|
||||
*this = 0L;
|
||||
|
|
@ -363,7 +390,7 @@ value_t& value_t::operator*=(const value_t& value)
|
|||
|
||||
switch (type) {
|
||||
case BOOLEAN:
|
||||
throw value_error("Cannot multiply a value by a boolean");
|
||||
throw new value_error("Cannot multiply a value by a boolean");
|
||||
|
||||
case INTEGER:
|
||||
switch (value.type) {
|
||||
|
|
@ -461,13 +488,13 @@ value_t& value_t::operator*=(const value_t& value)
|
|||
value_t& value_t::operator/=(const value_t& value)
|
||||
{
|
||||
if (value.type == BOOLEAN)
|
||||
throw value_error("Cannot divide a boolean by a value");
|
||||
throw new value_error("Cannot divide a boolean by a value");
|
||||
else if (value.type == DATETIME)
|
||||
throw value_error("Cannot divide a date/time by a value");
|
||||
throw new value_error("Cannot divide a date/time by a value");
|
||||
|
||||
switch (type) {
|
||||
case BOOLEAN:
|
||||
throw value_error("Cannot divide a value by a boolean");
|
||||
throw new value_error("Cannot divide a value by a boolean");
|
||||
|
||||
case INTEGER:
|
||||
switch (value.type) {
|
||||
|
|
@ -626,7 +653,7 @@ bool value_t::operator OP(const value_t& value) \
|
|||
case DATETIME: \
|
||||
switch (value.type) { \
|
||||
case BOOLEAN: \
|
||||
throw value_error("Cannot compare a date/time to a boolean"); \
|
||||
throw new value_error("Cannot compare a date/time to a boolean"); \
|
||||
\
|
||||
case INTEGER: \
|
||||
return (*((datetime_t *) data) OP \
|
||||
|
|
@ -637,13 +664,13 @@ bool value_t::operator OP(const value_t& value) \
|
|||
*((datetime_t *) value.data)); \
|
||||
\
|
||||
case AMOUNT: \
|
||||
throw value_error("Cannot compare a date/time to an amount"); \
|
||||
throw new value_error("Cannot compare a date/time to an amount"); \
|
||||
\
|
||||
case BALANCE: \
|
||||
throw value_error("Cannot compare a date/time to a balance"); \
|
||||
throw new value_error("Cannot compare a date/time to a balance"); \
|
||||
\
|
||||
case BALANCE_PAIR: \
|
||||
throw value_error("Cannot compare a date/time to a balance pair"); \
|
||||
throw new value_error("Cannot compare a date/time to a balance pair"); \
|
||||
\
|
||||
default: \
|
||||
assert(0); \
|
||||
|
|
@ -654,14 +681,14 @@ bool value_t::operator OP(const value_t& value) \
|
|||
case AMOUNT: \
|
||||
switch (value.type) { \
|
||||
case BOOLEAN: \
|
||||
throw value_error("Cannot compare an amount to a boolean"); \
|
||||
throw new value_error("Cannot compare an amount to a boolean"); \
|
||||
\
|
||||
case INTEGER: \
|
||||
return (*((amount_t *) data) OP \
|
||||
amount_t(*((long *) value.data))); \
|
||||
\
|
||||
case DATETIME: \
|
||||
throw value_error("Cannot compare an amount to a date/time"); \
|
||||
throw new value_error("Cannot compare an amount to a date/time"); \
|
||||
\
|
||||
case AMOUNT: \
|
||||
return *((amount_t *) data) OP *((amount_t *) value.data); \
|
||||
|
|
@ -685,13 +712,13 @@ bool value_t::operator OP(const value_t& value) \
|
|||
case BALANCE: \
|
||||
switch (value.type) { \
|
||||
case BOOLEAN: \
|
||||
throw value_error("Cannot compare a balance to a boolean"); \
|
||||
throw new value_error("Cannot compare a balance to a boolean"); \
|
||||
\
|
||||
case INTEGER: \
|
||||
return *((balance_t *) data) OP *((long *) value.data); \
|
||||
\
|
||||
case DATETIME: \
|
||||
throw value_error("Cannot compare a balance to a date/time"); \
|
||||
throw new value_error("Cannot compare a balance to a date/time"); \
|
||||
\
|
||||
case AMOUNT: \
|
||||
return *((balance_t *) data) OP *((amount_t *) value.data); \
|
||||
|
|
@ -712,14 +739,14 @@ bool value_t::operator OP(const value_t& value) \
|
|||
case BALANCE_PAIR: \
|
||||
switch (value.type) { \
|
||||
case BOOLEAN: \
|
||||
throw value_error("Cannot compare a balance pair to a boolean"); \
|
||||
throw new value_error("Cannot compare a balance pair to a boolean"); \
|
||||
\
|
||||
case INTEGER: \
|
||||
return (((balance_pair_t *) data)->quantity OP \
|
||||
*((long *) value.data)); \
|
||||
\
|
||||
case DATETIME: \
|
||||
throw value_error("Cannot compare a balance pair to a date/time"); \
|
||||
throw new value_error("Cannot compare a balance pair to a date/time"); \
|
||||
\
|
||||
case AMOUNT: \
|
||||
return (((balance_pair_t *) data)->quantity OP \
|
||||
|
|
@ -757,7 +784,7 @@ value_t::operator long() const
|
|||
{
|
||||
switch (type) {
|
||||
case BOOLEAN:
|
||||
throw value_error("Cannot convert a boolean to an integer");
|
||||
throw new value_error("Cannot convert a boolean to an integer");
|
||||
case INTEGER:
|
||||
return *((long *) data);
|
||||
case DATETIME:
|
||||
|
|
@ -765,9 +792,9 @@ value_t::operator long() const
|
|||
case AMOUNT:
|
||||
return *((amount_t *) data);
|
||||
case BALANCE:
|
||||
throw value_error("Cannot convert a balance to an integer");
|
||||
throw new value_error("Cannot convert a balance to an integer");
|
||||
case BALANCE_PAIR:
|
||||
throw value_error("Cannot convert a balance pair to an integer");
|
||||
throw new value_error("Cannot convert a balance pair to an integer");
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
|
|
@ -782,17 +809,17 @@ value_t::operator datetime_t() const
|
|||
{
|
||||
switch (type) {
|
||||
case BOOLEAN:
|
||||
throw value_error("Cannot convert a boolean to a date/time");
|
||||
throw new value_error("Cannot convert a boolean to a date/time");
|
||||
case INTEGER:
|
||||
return *((long *) data);
|
||||
case DATETIME:
|
||||
return *((datetime_t *) data);
|
||||
case AMOUNT:
|
||||
throw value_error("Cannot convert an amount to a date/time");
|
||||
throw new value_error("Cannot convert an amount to a date/time");
|
||||
case BALANCE:
|
||||
throw value_error("Cannot convert a balance to a date/time");
|
||||
throw new value_error("Cannot convert a balance to a date/time");
|
||||
case BALANCE_PAIR:
|
||||
throw value_error("Cannot convert a balance pair to a date/time");
|
||||
throw new value_error("Cannot convert a balance pair to a date/time");
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
|
|
@ -807,7 +834,7 @@ value_t::operator double() const
|
|||
{
|
||||
switch (type) {
|
||||
case BOOLEAN:
|
||||
throw value_error("Cannot convert a boolean to a double");
|
||||
throw new value_error("Cannot convert a boolean to a double");
|
||||
case INTEGER:
|
||||
return *((long *) data);
|
||||
case DATETIME:
|
||||
|
|
@ -815,9 +842,9 @@ value_t::operator double() const
|
|||
case AMOUNT:
|
||||
return *((amount_t *) data);
|
||||
case BALANCE:
|
||||
throw value_error("Cannot convert a balance to a double");
|
||||
throw new value_error("Cannot convert a balance to a double");
|
||||
case BALANCE_PAIR:
|
||||
throw value_error("Cannot convert a balance pair to a double");
|
||||
throw new value_error("Cannot convert a balance pair to a double");
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
|
|
@ -835,15 +862,15 @@ void value_t::cast(type_t cast_type)
|
|||
case BOOLEAN:
|
||||
break;
|
||||
case INTEGER:
|
||||
throw value_error("Cannot convert a boolean to an integer");
|
||||
throw new value_error("Cannot convert a boolean to an integer");
|
||||
case DATETIME:
|
||||
throw value_error("Cannot convert a boolean to a date/time");
|
||||
throw new value_error("Cannot convert a boolean to a date/time");
|
||||
case AMOUNT:
|
||||
throw value_error("Cannot convert a boolean to an amount");
|
||||
throw new value_error("Cannot convert a boolean to an amount");
|
||||
case BALANCE:
|
||||
throw value_error("Cannot convert a boolean to a balance");
|
||||
throw new value_error("Cannot convert a boolean to a balance");
|
||||
case BALANCE_PAIR:
|
||||
throw value_error("Cannot convert a boolean to a balance pair");
|
||||
throw new value_error("Cannot convert a boolean to a balance pair");
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
|
|
@ -888,11 +915,11 @@ void value_t::cast(type_t cast_type)
|
|||
case DATETIME:
|
||||
break;
|
||||
case AMOUNT:
|
||||
throw value_error("Cannot convert a date/time to an amount");
|
||||
throw new value_error("Cannot convert a date/time to an amount");
|
||||
case BALANCE:
|
||||
throw value_error("Cannot convert a date/time to a balance");
|
||||
throw new value_error("Cannot convert a date/time to a balance");
|
||||
case BALANCE_PAIR:
|
||||
throw value_error("Cannot convert a date/time to a balance pair");
|
||||
throw new value_error("Cannot convert a date/time to a balance pair");
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
|
|
@ -915,7 +942,7 @@ void value_t::cast(type_t cast_type)
|
|||
break;
|
||||
}
|
||||
case DATETIME:
|
||||
throw value_error("Cannot convert an amount to a date/time");
|
||||
throw new value_error("Cannot convert an amount to a date/time");
|
||||
case AMOUNT:
|
||||
break;
|
||||
case BALANCE: {
|
||||
|
|
@ -946,9 +973,9 @@ void value_t::cast(type_t cast_type)
|
|||
break;
|
||||
}
|
||||
case INTEGER:
|
||||
throw value_error("Cannot convert a balance to an integer");
|
||||
throw new value_error("Cannot convert a balance to an integer");
|
||||
case DATETIME:
|
||||
throw value_error("Cannot convert a balance to a date/time");
|
||||
throw new value_error("Cannot convert a balance to a date/time");
|
||||
|
||||
case AMOUNT: {
|
||||
balance_t * temp = (balance_t *) data;
|
||||
|
|
@ -961,7 +988,7 @@ void value_t::cast(type_t cast_type)
|
|||
new((amount_t *)data) amount_t();
|
||||
}
|
||||
else {
|
||||
throw value_error("Cannot convert a balance with "
|
||||
throw new value_error("Cannot convert a balance with "
|
||||
"multiple commodities to an amount");
|
||||
}
|
||||
break;
|
||||
|
|
@ -990,9 +1017,9 @@ void value_t::cast(type_t cast_type)
|
|||
break;
|
||||
}
|
||||
case INTEGER:
|
||||
throw value_error("Cannot convert a balance pair to an integer");
|
||||
throw new value_error("Cannot convert a balance pair to an integer");
|
||||
case DATETIME:
|
||||
throw value_error("Cannot convert a balance pair to a date/time");
|
||||
throw new value_error("Cannot convert a balance pair to a date/time");
|
||||
|
||||
case AMOUNT: {
|
||||
balance_t * temp = &((balance_pair_t *) data)->quantity;
|
||||
|
|
@ -1005,7 +1032,7 @@ void value_t::cast(type_t cast_type)
|
|||
new((amount_t *)data) amount_t();
|
||||
}
|
||||
else {
|
||||
throw value_error("Cannot convert a balance pair with "
|
||||
throw new value_error("Cannot convert a balance pair with "
|
||||
"multiple commodities to an amount");
|
||||
}
|
||||
break;
|
||||
|
|
@ -1042,7 +1069,7 @@ void value_t::negate()
|
|||
*((long *) data) = - *((long *) data);
|
||||
break;
|
||||
case DATETIME:
|
||||
throw value_error("Cannot negate a date/time");
|
||||
throw new value_error("Cannot negate a date/time");
|
||||
case AMOUNT:
|
||||
((amount_t *) data)->negate();
|
||||
break;
|
||||
|
|
@ -1090,9 +1117,9 @@ value_t value_t::value(const std::time_t moment) const
|
|||
{
|
||||
switch (type) {
|
||||
case BOOLEAN:
|
||||
throw value_error("Cannot find the value of a boolean");
|
||||
throw new value_error("Cannot find the value of a boolean");
|
||||
case DATETIME:
|
||||
throw value_error("Cannot find the value of a date/time");
|
||||
throw new value_error("Cannot find the value of a date/time");
|
||||
case INTEGER:
|
||||
return *this;
|
||||
case AMOUNT:
|
||||
|
|
@ -1108,9 +1135,9 @@ void value_t::round()
|
|||
{
|
||||
switch (type) {
|
||||
case BOOLEAN:
|
||||
throw value_error("Cannot round a boolean");
|
||||
throw new value_error("Cannot round a boolean");
|
||||
case DATETIME:
|
||||
throw value_error("Cannot round a date/time");
|
||||
throw new value_error("Cannot round a date/time");
|
||||
case INTEGER:
|
||||
break;
|
||||
case AMOUNT:
|
||||
|
|
@ -1125,15 +1152,38 @@ void value_t::round()
|
|||
}
|
||||
}
|
||||
|
||||
value_t value_t::unround() const
|
||||
{
|
||||
value_t temp;
|
||||
switch (type) {
|
||||
case BOOLEAN:
|
||||
throw new value_error("Cannot un-round a boolean");
|
||||
case DATETIME:
|
||||
throw new value_error("Cannot un-round a date/time");
|
||||
case INTEGER:
|
||||
break;
|
||||
case AMOUNT:
|
||||
temp = ((amount_t *) data)->unround();
|
||||
break;
|
||||
case BALANCE:
|
||||
temp = ((balance_t *) data)->unround();
|
||||
break;
|
||||
case BALANCE_PAIR:
|
||||
temp = ((balance_pair_t *) data)->unround();
|
||||
break;
|
||||
}
|
||||
return temp;
|
||||
}
|
||||
|
||||
value_t value_t::price() const
|
||||
{
|
||||
switch (type) {
|
||||
case BOOLEAN:
|
||||
throw value_error("Cannot find the price of a boolean");
|
||||
throw new value_error("Cannot find the price of a boolean");
|
||||
case INTEGER:
|
||||
return *this;
|
||||
case DATETIME:
|
||||
throw value_error("Cannot find the price of a date/time");
|
||||
throw new value_error("Cannot find the price of a date/time");
|
||||
|
||||
case AMOUNT:
|
||||
return ((amount_t *) data)->price();
|
||||
|
|
@ -1156,7 +1206,7 @@ value_t value_t::date() const
|
|||
{
|
||||
switch (type) {
|
||||
case BOOLEAN:
|
||||
throw value_error("Cannot find the date of a boolean");
|
||||
throw new value_error("Cannot find the date of a boolean");
|
||||
case INTEGER:
|
||||
return 0L;
|
||||
case DATETIME:
|
||||
|
|
@ -1185,11 +1235,11 @@ value_t value_t::strip_annotations(const bool keep_price,
|
|||
{
|
||||
switch (type) {
|
||||
case BOOLEAN:
|
||||
throw value_error("Cannot strip commodity annotations from a boolean");
|
||||
throw new value_error("Cannot strip commodity annotations from a boolean");
|
||||
case INTEGER:
|
||||
return *this;
|
||||
case DATETIME:
|
||||
throw value_error("Cannot strip commodity annotations from a date/time");
|
||||
throw new value_error("Cannot strip commodity annotations from a date/time");
|
||||
|
||||
case AMOUNT:
|
||||
return ((amount_t *) data)->strip_annotations
|
||||
|
|
@ -1213,13 +1263,13 @@ value_t value_t::cost() const
|
|||
{
|
||||
switch (type) {
|
||||
case BOOLEAN:
|
||||
throw value_error("Cannot find the cost of a boolean");
|
||||
throw new value_error("Cannot find the cost of a boolean");
|
||||
case INTEGER:
|
||||
case AMOUNT:
|
||||
case BALANCE:
|
||||
return *this;
|
||||
case DATETIME:
|
||||
throw value_error("Cannot find the cost of a date/time");
|
||||
throw new value_error("Cannot find the cost of a date/time");
|
||||
|
||||
case BALANCE_PAIR:
|
||||
assert(((balance_pair_t *) data)->cost);
|
||||
|
|
@ -1240,9 +1290,9 @@ value_t& value_t::add(const amount_t& amount, const amount_t * cost)
|
|||
{
|
||||
switch (type) {
|
||||
case BOOLEAN:
|
||||
throw value_error("Cannot add an amount to a boolean");
|
||||
throw new value_error("Cannot add an amount to a boolean");
|
||||
case DATETIME:
|
||||
throw value_error("Cannot add an amount to a date/time");
|
||||
throw new value_error("Cannot add an amount to a date/time");
|
||||
case INTEGER:
|
||||
case AMOUNT:
|
||||
if (cost) {
|
||||
|
|
@ -1329,13 +1379,13 @@ amount_t value_getitem(value_t& value, int i)
|
|||
|
||||
switch (value.type) {
|
||||
case value_t::BOOLEAN:
|
||||
throw value_error("Cannot cast a boolean to an amount");
|
||||
throw new value_error("Cannot cast a boolean to an amount");
|
||||
|
||||
case value_t::INTEGER:
|
||||
return long(value);
|
||||
|
||||
case value_t::DATETIME:
|
||||
throw value_error("Cannot cast a date/time to an amount");
|
||||
throw new value_error("Cannot cast a date/time to an amount");
|
||||
|
||||
case value_t::AMOUNT:
|
||||
return *((amount_t *) value.data);
|
||||
|
|
@ -1555,7 +1605,6 @@ void export_value()
|
|||
.def("__len__", value_len)
|
||||
.def("__getitem__", value_getitem)
|
||||
|
||||
.def("abs", &value_t::abs)
|
||||
.def("cast", &value_t::cast)
|
||||
.def("cost", &value_t::cost)
|
||||
.def("price", &value_t::price)
|
||||
|
|
|
|||
12
value.h
12
value.h
|
|
@ -8,17 +8,6 @@
|
|||
|
||||
namespace ledger {
|
||||
|
||||
class value_error : public std::exception {
|
||||
std::string reason;
|
||||
public:
|
||||
value_error(const std::string& _reason) throw() : reason(_reason) {}
|
||||
virtual ~value_error() throw() {}
|
||||
|
||||
virtual const char* what() const throw() {
|
||||
return reason.c_str();
|
||||
}
|
||||
};
|
||||
|
||||
// The following type is a polymorphous value type used solely for
|
||||
// performance reasons. The alternative is to compute value
|
||||
// expressions (valexpr.cc) in terms of the largest data type,
|
||||
|
|
@ -327,6 +316,7 @@ class value_t
|
|||
value_t& add(const amount_t& amount, const amount_t * cost = NULL);
|
||||
value_t value(const std::time_t moment) const;
|
||||
void round();
|
||||
value_t unround() const;
|
||||
};
|
||||
|
||||
#define DEF_VALUE_AUX_OP(OP) \
|
||||
|
|
|
|||
25
walk.cc
25
walk.cc
|
|
@ -16,13 +16,13 @@ bool compare_items<transaction_t>::operator()(const transaction_t * left,
|
|||
|
||||
transaction_xdata_t& lxdata(transaction_xdata(*left));
|
||||
if (! (lxdata.dflags & TRANSACTION_SORT_CALC)) {
|
||||
sort_order->compute(lxdata.sort_value, details_t(*left));
|
||||
guarded_compute(sort_order, lxdata.sort_value, details_t(*left));
|
||||
lxdata.dflags |= TRANSACTION_SORT_CALC;
|
||||
}
|
||||
|
||||
transaction_xdata_t& rxdata(transaction_xdata(*right));
|
||||
if (! (rxdata.dflags & TRANSACTION_SORT_CALC)) {
|
||||
sort_order->compute(rxdata.sort_value, details_t(*right));
|
||||
guarded_compute(sort_order, rxdata.sort_value, details_t(*right));
|
||||
rxdata.dflags |= TRANSACTION_SORT_CALC;
|
||||
}
|
||||
|
||||
|
|
@ -133,6 +133,8 @@ void sort_transactions::post_accumulated_xacts()
|
|||
|
||||
void calc_transactions::operator()(transaction_t& xact)
|
||||
{
|
||||
try {
|
||||
|
||||
transaction_xdata_t& xdata(transaction_xdata(xact));
|
||||
|
||||
if (last_xact && transaction_has_xdata(*last_xact)) {
|
||||
|
|
@ -148,6 +150,13 @@ void calc_transactions::operator()(transaction_t& xact)
|
|||
item_handler<transaction_t>::operator()(xact);
|
||||
|
||||
last_xact = &xact;
|
||||
|
||||
}
|
||||
catch (error * err) {
|
||||
err->context.push_front
|
||||
(new xact_context(xact, "Calculating transaction at"));
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
void invert_transactions::operator()(transaction_t& xact)
|
||||
|
|
@ -710,13 +719,13 @@ bool compare_items<account_t>::operator()(const account_t * left,
|
|||
|
||||
account_xdata_t& lxdata(account_xdata(*left));
|
||||
if (! (lxdata.dflags & ACCOUNT_SORT_CALC)) {
|
||||
sort_order->compute(lxdata.sort_value, details_t(*left));
|
||||
guarded_compute(sort_order, lxdata.sort_value, details_t(*left));
|
||||
lxdata.dflags |= ACCOUNT_SORT_CALC;
|
||||
}
|
||||
|
||||
account_xdata_t& rxdata(account_xdata(*right));
|
||||
if (! (rxdata.dflags & ACCOUNT_SORT_CALC)) {
|
||||
sort_order->compute(rxdata.sort_value, details_t(*right));
|
||||
guarded_compute(sort_order, rxdata.sort_value, details_t(*right));
|
||||
rxdata.dflags |= ACCOUNT_SORT_CALC;
|
||||
}
|
||||
|
||||
|
|
@ -794,13 +803,7 @@ void walk_accounts(account_t& account,
|
|||
{
|
||||
if (! sort_string.empty()) {
|
||||
value_auto_ptr sort_order;
|
||||
try {
|
||||
sort_order.reset(parse_value_expr(sort_string));
|
||||
}
|
||||
catch (value_expr_error& err) {
|
||||
throw error(std::string("In sort string '" + sort_string + "': " +
|
||||
err.what()));
|
||||
}
|
||||
sort_order.reset(parse_value_expr(sort_string));
|
||||
walk_accounts(account, handler, sort_order.get());
|
||||
} else {
|
||||
walk_accounts(account, handler);
|
||||
|
|
|
|||
16
walk.h
16
walk.h
|
|
@ -23,10 +23,10 @@ struct item_handler {
|
|||
item_handler(item_handler * _handler) : handler(_handler) {
|
||||
DEBUG_PRINT("ledger.memory.ctors", "ctor item_handler<T>");
|
||||
}
|
||||
|
||||
virtual ~item_handler() {
|
||||
DEBUG_PRINT("ledger.memory.dtors", "dtor item_handler<T>");
|
||||
}
|
||||
|
||||
virtual void flush() {
|
||||
if (handler)
|
||||
handler->flush();
|
||||
|
|
@ -56,8 +56,8 @@ bool compare_items<T>::operator()(const T * left, const T * right)
|
|||
|
||||
value_t left_result;
|
||||
value_t right_result;
|
||||
sort_order->compute(left_result, details_t(*left));
|
||||
sort_order->compute(right_result, details_t(*right));
|
||||
guarded_compute(sort_order, left_result, details_t(*left));
|
||||
guarded_compute(sort_order, right_result, details_t(*right));
|
||||
|
||||
return left_result < right_result;
|
||||
}
|
||||
|
|
@ -222,14 +222,8 @@ class sort_transactions : public item_handler<transaction_t>
|
|||
sort_transactions(item_handler<transaction_t> * handler,
|
||||
const std::string& _sort_order)
|
||||
: item_handler<transaction_t>(handler) {
|
||||
try {
|
||||
sort_order = parse_value_expr(_sort_order);
|
||||
sort_order->acquire();
|
||||
}
|
||||
catch (value_expr_error& err) {
|
||||
throw value_expr_error(std::string("In sort string '") + _sort_order +
|
||||
"': " + err.what());
|
||||
}
|
||||
assert(! _sort_order.empty());
|
||||
sort_order = parse_value_expr(_sort_order)->acquire();
|
||||
}
|
||||
|
||||
virtual ~sort_transactions() {
|
||||
|
|
|
|||
8
xml.cc
8
xml.cc
|
|
@ -223,14 +223,12 @@ unsigned int xml_parser_t::parse(std::istream& in,
|
|||
catch (const std::exception& err) {
|
||||
unsigned long line = XML_GetCurrentLineNumber(parser) - offset++;
|
||||
XML_ParserFree(parser);
|
||||
throw parse_error(original_file ? *original_file : "<xml>", line,
|
||||
err.what());
|
||||
throw new parse_error(err.what());
|
||||
}
|
||||
|
||||
if (! have_error.empty()) {
|
||||
unsigned long line = XML_GetCurrentLineNumber(parser) - offset++;
|
||||
parse_error err(original_file ? *original_file : "<xml>", line,
|
||||
have_error);
|
||||
parse_error err(have_error);
|
||||
std::cerr << "Error: " << err.what() << std::endl;
|
||||
have_error = "";
|
||||
}
|
||||
|
|
@ -239,7 +237,7 @@ unsigned int xml_parser_t::parse(std::istream& in,
|
|||
unsigned long line = XML_GetCurrentLineNumber(parser) - offset++;
|
||||
const char * err = XML_ErrorString(XML_GetErrorCode(parser));
|
||||
XML_ParserFree(parser);
|
||||
throw parse_error(original_file ? *original_file : "<xml>", line, err);
|
||||
throw new parse_error(err);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue