*** empty log message ***
This commit is contained in:
parent
2964dd15b2
commit
b1a04923fe
8 changed files with 196 additions and 218 deletions
267
amount.cc
267
amount.cc
|
|
@ -378,8 +378,11 @@ amount_t& amount_t::operator+=(const amount_t& amt)
|
||||||
|
|
||||||
_dup();
|
_dup();
|
||||||
|
|
||||||
if (commodity_ != amt.commodity_)
|
if (commodity() != amt.commodity())
|
||||||
throw new amount_error("Adding amounts with different commodities");
|
throw new amount_error
|
||||||
|
(std::string("Adding amounts with different commodities: ") +
|
||||||
|
commodity_->qualified_symbol + " != " +
|
||||||
|
amt.commodity_->qualified_symbol);
|
||||||
|
|
||||||
if (quantity->prec == amt.quantity->prec) {
|
if (quantity->prec == amt.quantity->prec) {
|
||||||
mpz_add(MPZ(quantity), MPZ(quantity), MPZ(amt.quantity));
|
mpz_add(MPZ(quantity), MPZ(quantity), MPZ(amt.quantity));
|
||||||
|
|
@ -411,8 +414,11 @@ amount_t& amount_t::operator-=(const amount_t& amt)
|
||||||
|
|
||||||
_dup();
|
_dup();
|
||||||
|
|
||||||
if (commodity_ != amt.commodity_)
|
if (commodity() != amt.commodity())
|
||||||
throw new amount_error("Subtracting amounts with different commodities");
|
throw new amount_error
|
||||||
|
(std::string("Subtracting amounts with different commodities: ") +
|
||||||
|
commodity_->qualified_symbol + " != " +
|
||||||
|
amt.commodity_->qualified_symbol);
|
||||||
|
|
||||||
if (quantity->prec == amt.quantity->prec) {
|
if (quantity->prec == amt.quantity->prec) {
|
||||||
mpz_sub(MPZ(quantity), MPZ(quantity), MPZ(amt.quantity));
|
mpz_sub(MPZ(quantity), MPZ(quantity), MPZ(amt.quantity));
|
||||||
|
|
@ -533,10 +539,10 @@ amount_t::operator bool() const
|
||||||
return mpz_sgn(MPZ(quantity)) != 0;
|
return mpz_sgn(MPZ(quantity)) != 0;
|
||||||
} else {
|
} else {
|
||||||
mpz_set(temp, MPZ(quantity));
|
mpz_set(temp, MPZ(quantity));
|
||||||
if (commodity_)
|
if (quantity->flags & BIGINT_KEEP_PREC)
|
||||||
mpz_ui_pow_ui(divisor, 10, quantity->prec - commodity().precision());
|
|
||||||
else
|
|
||||||
mpz_ui_pow_ui(divisor, 10, quantity->prec);
|
mpz_ui_pow_ui(divisor, 10, quantity->prec);
|
||||||
|
else
|
||||||
|
mpz_ui_pow_ui(divisor, 10, quantity->prec - commodity().precision());
|
||||||
mpz_tdiv_q(temp, temp, divisor);
|
mpz_tdiv_q(temp, temp, divisor);
|
||||||
bool zero = mpz_sgn(temp) == 0;
|
bool zero = mpz_sgn(temp) == 0;
|
||||||
return ! zero;
|
return ! zero;
|
||||||
|
|
@ -600,22 +606,37 @@ amount_t amount_t::value(const std::time_t moment) const
|
||||||
|
|
||||||
amount_t amount_t::round(unsigned int prec) const
|
amount_t amount_t::round(unsigned int prec) const
|
||||||
{
|
{
|
||||||
if (! quantity || quantity->prec <= prec)
|
|
||||||
return *this;
|
|
||||||
|
|
||||||
amount_t temp = *this;
|
amount_t temp = *this;
|
||||||
|
|
||||||
|
if (! quantity || quantity->prec <= prec) {
|
||||||
|
if (quantity->flags & BIGINT_KEEP_PREC) {
|
||||||
|
temp._dup();
|
||||||
|
temp.quantity->flags &= ~BIGINT_KEEP_PREC;
|
||||||
|
}
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
temp._dup();
|
temp._dup();
|
||||||
|
|
||||||
mpz_round(MPZ(temp.quantity), MPZ(temp.quantity), temp.quantity->prec, prec);
|
mpz_round(MPZ(temp.quantity), MPZ(temp.quantity), temp.quantity->prec, prec);
|
||||||
|
|
||||||
temp.quantity->prec = prec;
|
temp.quantity->prec = prec;
|
||||||
|
temp.quantity->flags &= ~BIGINT_KEEP_PREC;
|
||||||
|
|
||||||
return temp;
|
return temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
amount_t amount_t::unround() const
|
amount_t amount_t::unround() const
|
||||||
{
|
{
|
||||||
if (! quantity || quantity->flags & BIGINT_KEEP_PREC)
|
if (! quantity) {
|
||||||
|
amount_t temp(0L);
|
||||||
|
assert(temp.quantity);
|
||||||
|
temp.quantity->flags |= BIGINT_KEEP_PREC;
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
else if (quantity->flags & BIGINT_KEEP_PREC) {
|
||||||
return *this;
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
amount_t temp = *this;
|
amount_t temp = *this;
|
||||||
temp._dup();
|
temp._dup();
|
||||||
|
|
@ -731,7 +752,7 @@ std::ostream& operator<<(std::ostream& _out, const amount_t& amt)
|
||||||
last.commodity_ = last.commodity().larger()->commodity_;
|
last.commodity_ = last.commodity().larger()->commodity_;
|
||||||
if (ledger::abs(last) < 1)
|
if (ledger::abs(last) < 1)
|
||||||
break;
|
break;
|
||||||
base = last;
|
base = last.round();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -849,8 +870,6 @@ std::ostream& operator<<(std::ostream& _out, const amount_t& amt)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (precision) {
|
if (precision) {
|
||||||
out << ((comm.flags() & COMMODITY_STYLE_EUROPEAN) ? ',' : '.');
|
|
||||||
|
|
||||||
std::ostringstream final;
|
std::ostringstream final;
|
||||||
final.width(precision);
|
final.width(precision);
|
||||||
final.fill('0');
|
final.fill('0');
|
||||||
|
|
@ -865,12 +884,18 @@ std::ostream& operator<<(std::ostream& _out, const amount_t& amt)
|
||||||
if (q[i - 1] != '0')
|
if (q[i - 1] != '0')
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
std::string ender;
|
||||||
if (i == len)
|
if (i == len)
|
||||||
out << str;
|
ender = str;
|
||||||
else if (i < comm.precision())
|
else if (i < comm.precision())
|
||||||
out << std::string(str, 0, comm.precision());
|
ender = std::string(str, 0, comm.precision());
|
||||||
else
|
else
|
||||||
out << std::string(str, 0, i);
|
ender = std::string(str, 0, i);
|
||||||
|
|
||||||
|
if (! ender.empty()) {
|
||||||
|
out << ((comm.flags() & COMMODITY_STYLE_EUROPEAN) ? ',' : '.');
|
||||||
|
out << ender;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (comm.flags() & COMMODITY_STYLE_SUFFIXED) {
|
if (comm.flags() & COMMODITY_STYLE_SUFFIXED) {
|
||||||
|
|
@ -889,6 +914,7 @@ std::ostream& operator<<(std::ostream& _out, const amount_t& amt)
|
||||||
|
|
||||||
if (comm.annotated) {
|
if (comm.annotated) {
|
||||||
annotated_commodity_t& ann(static_cast<annotated_commodity_t&>(comm));
|
annotated_commodity_t& ann(static_cast<annotated_commodity_t&>(comm));
|
||||||
|
assert(&ann.price != &amt);
|
||||||
ann.write_annotations(out);
|
ann.write_annotations(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -928,18 +954,14 @@ void parse_commodity(std::istream& in, std::string& symbol)
|
||||||
symbol = buf;
|
symbol = buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
void parse_annotations(std::istream& in, const std::string& symbol,
|
void parse_annotations(std::istream& in, amount_t& price,
|
||||||
std::string& name, std::string& price,
|
std::time_t& date, std::string& tag)
|
||||||
std::string& date, std::string& tag)
|
|
||||||
{
|
{
|
||||||
char buf[256];
|
|
||||||
|
|
||||||
bool added_name = false;
|
|
||||||
bool handled = false;
|
|
||||||
do {
|
do {
|
||||||
|
char buf[256];
|
||||||
char c = peek_next_nonws(in);
|
char c = peek_next_nonws(in);
|
||||||
if (c == '{') {
|
if (c == '{') {
|
||||||
if (! price.empty())
|
if (price)
|
||||||
throw new amount_error("Commodity specifies more than one price");
|
throw new amount_error("Commodity specifies more than one price");
|
||||||
|
|
||||||
in.get(c);
|
in.get(c);
|
||||||
|
|
@ -948,21 +970,12 @@ void parse_annotations(std::istream& in, const std::string& symbol,
|
||||||
in.get(c);
|
in.get(c);
|
||||||
else
|
else
|
||||||
throw new amount_error("Commodity price lacks closing brace");
|
throw new amount_error("Commodity price lacks closing brace");
|
||||||
price = buf;
|
|
||||||
if (! added_name) {
|
price.parse(buf, AMOUNT_PARSE_NO_MIGRATE);
|
||||||
added_name = true;
|
price.reduce();
|
||||||
if (commodity_t::needs_quotes(symbol)) {
|
|
||||||
name = "\"";
|
|
||||||
name += symbol;
|
|
||||||
name += "\"";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
name += " {";
|
|
||||||
name += price;
|
|
||||||
name += "}";
|
|
||||||
}
|
}
|
||||||
else if (c == '[') {
|
else if (c == '[') {
|
||||||
if (! date.empty())
|
if (date)
|
||||||
throw new amount_error("Commodity specifies more than one date");
|
throw new amount_error("Commodity specifies more than one date");
|
||||||
|
|
||||||
in.get(c);
|
in.get(c);
|
||||||
|
|
@ -971,18 +984,8 @@ void parse_annotations(std::istream& in, const std::string& symbol,
|
||||||
in.get(c);
|
in.get(c);
|
||||||
else
|
else
|
||||||
throw new amount_error("Commodity date lacks closing bracket");
|
throw new amount_error("Commodity date lacks closing bracket");
|
||||||
date = buf;
|
|
||||||
if (! added_name) {
|
parse_date(buf, &date);
|
||||||
added_name = true;
|
|
||||||
if (commodity_t::needs_quotes(symbol)) {
|
|
||||||
name = "\"";
|
|
||||||
name += symbol;
|
|
||||||
name += "\"";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
name += " [";
|
|
||||||
name += date;
|
|
||||||
name += "]";
|
|
||||||
}
|
}
|
||||||
else if (c == '(') {
|
else if (c == '(') {
|
||||||
if (! tag.empty())
|
if (! tag.empty())
|
||||||
|
|
@ -994,27 +997,16 @@ void parse_annotations(std::istream& in, const std::string& symbol,
|
||||||
in.get(c);
|
in.get(c);
|
||||||
else
|
else
|
||||||
throw new amount_error("Commodity tag lacks closing parenthesis");
|
throw new amount_error("Commodity tag lacks closing parenthesis");
|
||||||
|
|
||||||
tag = buf;
|
tag = buf;
|
||||||
if (! added_name) {
|
|
||||||
added_name = true;
|
|
||||||
if (commodity_t::needs_quotes(symbol)) {
|
|
||||||
name = "\"";
|
|
||||||
name += symbol;
|
|
||||||
name += "\"";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
name += " (";
|
|
||||||
name += tag;
|
|
||||||
name += ")";
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} while (true);
|
} while (true);
|
||||||
|
|
||||||
DEBUG_PRINT("amounts.commodities", "Parsed commodity annotations: "
|
DEBUG_PRINT("amounts.commodities",
|
||||||
<< "name " << name << " "
|
"Parsed commodity annotations: "
|
||||||
<< "symbol " << symbol << std::endl
|
|
||||||
<< " price " << price << " "
|
<< " price " << price << " "
|
||||||
<< " date " << date << " "
|
<< " date " << date << " "
|
||||||
<< " tag " << tag);
|
<< " tag " << tag);
|
||||||
|
|
@ -1027,11 +1019,10 @@ void amount_t::parse(std::istream& in, unsigned char flags)
|
||||||
// [-]NUM[ ]SYM [@ AMOUNT]
|
// [-]NUM[ ]SYM [@ AMOUNT]
|
||||||
// SYM[ ][-]NUM [@ AMOUNT]
|
// SYM[ ][-]NUM [@ AMOUNT]
|
||||||
|
|
||||||
std::string name;
|
|
||||||
std::string symbol;
|
std::string symbol;
|
||||||
std::string quant;
|
std::string quant;
|
||||||
std::string price;
|
amount_t price;
|
||||||
std::string date;
|
std::time_t date = 0;
|
||||||
std::string tag;
|
std::string tag;
|
||||||
unsigned int comm_flags = COMMODITY_STYLE_DEFAULTS;
|
unsigned int comm_flags = COMMODITY_STYLE_DEFAULTS;
|
||||||
bool negative = false;
|
bool negative = false;
|
||||||
|
|
@ -1052,17 +1043,15 @@ void amount_t::parse(std::istream& in, unsigned char flags)
|
||||||
comm_flags |= COMMODITY_STYLE_SEPARATED;
|
comm_flags |= COMMODITY_STYLE_SEPARATED;
|
||||||
|
|
||||||
parse_commodity(in, symbol);
|
parse_commodity(in, symbol);
|
||||||
name = symbol;
|
|
||||||
|
|
||||||
if (! symbol.empty())
|
if (! symbol.empty())
|
||||||
comm_flags |= COMMODITY_STYLE_SUFFIXED;
|
comm_flags |= COMMODITY_STYLE_SUFFIXED;
|
||||||
|
|
||||||
if (! in.eof() && ((n = in.peek()) != '\n'))
|
if (! in.eof() && ((n = in.peek()) != '\n'))
|
||||||
parse_annotations(in, symbol, name, price, date, tag);
|
parse_annotations(in, price, date, tag);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
parse_commodity(in, symbol);
|
parse_commodity(in, symbol);
|
||||||
name = symbol;
|
|
||||||
|
|
||||||
if (! in.eof() && ((n = in.peek()) != '\n')) {
|
if (! in.eof() && ((n = in.peek()) != '\n')) {
|
||||||
if (std::isspace(in.peek()))
|
if (std::isspace(in.peek()))
|
||||||
|
|
@ -1071,7 +1060,7 @@ void amount_t::parse(std::istream& in, unsigned char flags)
|
||||||
parse_quantity(in, quant);
|
parse_quantity(in, quant);
|
||||||
|
|
||||||
if (! in.eof() && ((n = in.peek()) != '\n'))
|
if (! in.eof() && ((n = in.peek()) != '\n'))
|
||||||
parse_annotations(in, symbol, name, price, date, tag);
|
parse_annotations(in, price, date, tag);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1085,23 +1074,19 @@ void amount_t::parse(std::istream& in, unsigned char flags)
|
||||||
|
|
||||||
bool newly_created = false;
|
bool newly_created = false;
|
||||||
|
|
||||||
commodity_ = commodity_t::find(name);
|
if (symbol.empty()) {
|
||||||
if (! commodity_) {
|
commodity_ = commodity_t::null_commodity;
|
||||||
newly_created = true;
|
} else {
|
||||||
|
commodity_ = commodity_t::find(symbol);
|
||||||
if (! price.empty() || ! date.empty() || ! tag.empty()) {
|
if (! commodity_) {
|
||||||
commodity_ = annotated_commodity_t::create(symbol, price, date, tag);
|
|
||||||
} else {
|
|
||||||
assert(name == symbol);
|
|
||||||
commodity_ = commodity_t::create(symbol);
|
commodity_ = commodity_t::create(symbol);
|
||||||
|
newly_created = true;
|
||||||
}
|
}
|
||||||
#ifdef DEBUG_ENABLED
|
assert(commodity_);
|
||||||
if (! commodity_)
|
|
||||||
std::cerr << "Failed to find commodity for name "
|
if (price || date || ! tag.empty())
|
||||||
<< name << " symbol " << symbol << std::endl;
|
commodity_ =
|
||||||
#endif
|
annotated_commodity_t::find_or_create(*commodity_, price, date, tag);
|
||||||
if (! commodity_)
|
|
||||||
commodity_ = commodity_t::null_commodity;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine the precision of the amount, based on the usage of
|
// Determine the precision of the amount, based on the usage of
|
||||||
|
|
@ -1327,10 +1312,13 @@ void amount_t::write_quantity(std::ostream& out) const
|
||||||
bool amount_t::valid() const
|
bool amount_t::valid() const
|
||||||
{
|
{
|
||||||
if (quantity) {
|
if (quantity) {
|
||||||
if (quantity->ref == 0)
|
if (quantity->ref == 0) {
|
||||||
|
DEBUG_PRINT("ledger.validate", "amount_t: quantity->ref == 0");
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (commodity_) {
|
else if (commodity_) {
|
||||||
|
DEBUG_PRINT("ledger.validate", "amount_t: commodity_ != NULL");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -1448,16 +1436,21 @@ bool commodity_t::needs_quotes(const std::string& symbol)
|
||||||
|
|
||||||
bool commodity_t::valid() const
|
bool commodity_t::valid() const
|
||||||
{
|
{
|
||||||
if (symbol().empty() && this != null_commodity)
|
if (symbol().empty() && this != null_commodity) {
|
||||||
|
DEBUG_PRINT("ledger.validate",
|
||||||
|
"commodity_t: symbol().empty() && this != null_commodity");
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
#if 0
|
if (annotated && ! base) {
|
||||||
if (annotated && ! base)
|
DEBUG_PRINT("ledger.validate", "commodity_t: annotated && ! base");
|
||||||
return false;
|
return false;
|
||||||
#endif
|
}
|
||||||
|
|
||||||
if (precision() > 16)
|
if (precision() > 16) {
|
||||||
|
DEBUG_PRINT("ledger.validate", "commodity_t: precision() > 16");
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -1572,34 +1565,12 @@ annotated_commodity_t::write_annotations(std::ostream& out,
|
||||||
out << " (" << tag << ')';
|
out << " (" << tag << ')';
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string
|
|
||||||
annotated_commodity_t::make_qualified_name(const commodity_t& comm,
|
|
||||||
const amount_t& price,
|
|
||||||
const std::time_t date,
|
|
||||||
const std::string& tag)
|
|
||||||
{
|
|
||||||
std::ostringstream name;
|
|
||||||
|
|
||||||
comm.write(name);
|
|
||||||
write_annotations(name, price, date, tag);
|
|
||||||
|
|
||||||
DEBUG_PRINT("amounts.commodities", "make_qualified_name for "
|
|
||||||
<< comm.qualified_symbol << std::endl
|
|
||||||
<< " price " << price << " "
|
|
||||||
<< " date " << date << " "
|
|
||||||
<< " tag " << tag);
|
|
||||||
|
|
||||||
DEBUG_PRINT("amounts.commodities", "qualified_name is " << name.str());
|
|
||||||
|
|
||||||
return name.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
commodity_t *
|
commodity_t *
|
||||||
annotated_commodity_t::create(const commodity_t& comm,
|
annotated_commodity_t::create(const commodity_t& comm,
|
||||||
const amount_t& price,
|
const amount_t& price,
|
||||||
const std::time_t date,
|
const std::time_t date,
|
||||||
const std::string& tag,
|
const std::string& tag,
|
||||||
const std::string& entry_name)
|
const std::string& mapping_key)
|
||||||
{
|
{
|
||||||
std::auto_ptr<annotated_commodity_t> commodity(new annotated_commodity_t);
|
std::auto_ptr<annotated_commodity_t> commodity(new annotated_commodity_t);
|
||||||
|
|
||||||
|
|
@ -1615,12 +1586,6 @@ annotated_commodity_t::create(const commodity_t& comm,
|
||||||
|
|
||||||
commodity->qualified_symbol = comm.symbol();
|
commodity->qualified_symbol = comm.symbol();
|
||||||
|
|
||||||
std::string mapping_key;
|
|
||||||
if (entry_name.empty())
|
|
||||||
mapping_key = make_qualified_name(comm, price, date, tag);
|
|
||||||
else
|
|
||||||
mapping_key = entry_name;
|
|
||||||
|
|
||||||
DEBUG_PRINT("amounts.commodities", "Creating annotated commodity "
|
DEBUG_PRINT("amounts.commodities", "Creating annotated commodity "
|
||||||
<< "symbol " << commodity->symbol()
|
<< "symbol " << commodity->symbol()
|
||||||
<< " key " << mapping_key << std::endl
|
<< " key " << mapping_key << std::endl
|
||||||
|
|
@ -1638,39 +1603,27 @@ annotated_commodity_t::create(const commodity_t& comm,
|
||||||
return commodity.release();
|
return commodity.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
commodity_t *
|
namespace {
|
||||||
annotated_commodity_t::create(const std::string& symbol,
|
std::string make_qualified_name(const commodity_t& comm,
|
||||||
const amount_t& price,
|
const amount_t& price,
|
||||||
const std::time_t date,
|
const std::time_t date,
|
||||||
const std::string& tag)
|
const std::string& tag)
|
||||||
{
|
{
|
||||||
commodity_t * comm = commodity_t::find_or_create(symbol);
|
std::ostringstream name;
|
||||||
assert(comm);
|
|
||||||
|
|
||||||
if (! price && ! date && tag.empty())
|
comm.write(name);
|
||||||
return comm;
|
annotated_commodity_t::write_annotations(name, price, date, tag);
|
||||||
|
|
||||||
return create(*comm, price, date, tag);
|
DEBUG_PRINT("amounts.commodities", "make_qualified_name for "
|
||||||
}
|
<< comm.qualified_symbol << std::endl
|
||||||
|
<< " price " << price << " "
|
||||||
|
<< " date " << date << " "
|
||||||
|
<< " tag " << tag);
|
||||||
|
|
||||||
commodity_t *
|
DEBUG_PRINT("amounts.commodities", "qualified_name is " << name.str());
|
||||||
annotated_commodity_t::create(const std::string& symbol,
|
|
||||||
const std::string& price,
|
|
||||||
const std::string& date,
|
|
||||||
const std::string& tag)
|
|
||||||
{
|
|
||||||
commodity_t * comm = commodity_t::find_or_create(symbol);
|
|
||||||
assert(comm);
|
|
||||||
|
|
||||||
amount_t real_price;
|
return name.str();
|
||||||
if (! price.empty())
|
}
|
||||||
real_price.parse(price, AMOUNT_PARSE_NO_MIGRATE);
|
|
||||||
|
|
||||||
std::time_t real_date = 0;
|
|
||||||
if (! date.empty())
|
|
||||||
parse_date(date.c_str(), &real_date);
|
|
||||||
|
|
||||||
return create(*comm, real_price, real_date, tag);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
commodity_t *
|
commodity_t *
|
||||||
|
|
@ -1681,14 +1634,12 @@ annotated_commodity_t::find_or_create(const commodity_t& comm,
|
||||||
{
|
{
|
||||||
std::string name = make_qualified_name(comm, price, date, tag);
|
std::string name = make_qualified_name(comm, price, date, tag);
|
||||||
|
|
||||||
commodity_t * base = commodity_t::find(name);
|
commodity_t * ann_comm = commodity_t::find(name);
|
||||||
if (base)
|
if (ann_comm) {
|
||||||
return base;
|
assert(ann_comm->annotated);
|
||||||
|
return ann_comm;
|
||||||
base = commodity_t::find_or_create(comm.base_symbol());
|
}
|
||||||
assert(base);
|
return create(comm, price, date, tag, name);
|
||||||
|
|
||||||
return create(*base, price, date, tag, name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace ledger
|
} // namespace ledger
|
||||||
|
|
|
||||||
46
amount.h
46
amount.h
|
|
@ -551,33 +551,6 @@ class annotated_commodity_t : public commodity_t
|
||||||
std::time_t date;
|
std::time_t date;
|
||||||
std::string tag;
|
std::string tag;
|
||||||
|
|
||||||
static void write_annotations(std::ostream& out,
|
|
||||||
const amount_t& price,
|
|
||||||
const std::time_t date,
|
|
||||||
const std::string& tag);
|
|
||||||
static
|
|
||||||
std::string make_qualified_name(const commodity_t& comm,
|
|
||||||
const amount_t& price,
|
|
||||||
const std::time_t date,
|
|
||||||
const std::string& tag);
|
|
||||||
static commodity_t * create(const commodity_t& comm,
|
|
||||||
const amount_t& price,
|
|
||||||
const std::time_t date,
|
|
||||||
const std::string& tag,
|
|
||||||
const std::string& entry_name = "");
|
|
||||||
static commodity_t * create(const std::string& symbol,
|
|
||||||
const amount_t& price,
|
|
||||||
const std::time_t date,
|
|
||||||
const std::string& tag);
|
|
||||||
static commodity_t * create(const std::string& symbol,
|
|
||||||
const std::string& price,
|
|
||||||
const std::string& date,
|
|
||||||
const std::string& tag);
|
|
||||||
static commodity_t * find_or_create(const commodity_t& comm,
|
|
||||||
const amount_t& price,
|
|
||||||
const std::time_t date,
|
|
||||||
const std::string& tag);
|
|
||||||
|
|
||||||
explicit annotated_commodity_t() {
|
explicit annotated_commodity_t() {
|
||||||
annotated = true;
|
annotated = true;
|
||||||
}
|
}
|
||||||
|
|
@ -585,6 +558,25 @@ class annotated_commodity_t : public commodity_t
|
||||||
void write_annotations(std::ostream& out) const {
|
void write_annotations(std::ostream& out) const {
|
||||||
annotated_commodity_t::write_annotations(out, price, date, tag);
|
annotated_commodity_t::write_annotations(out, price, date, tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void write_annotations(std::ostream& out,
|
||||||
|
const amount_t& price,
|
||||||
|
const std::time_t date,
|
||||||
|
const std::string& tag);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static commodity_t * create(const commodity_t& comm,
|
||||||
|
const amount_t& price,
|
||||||
|
const std::time_t date,
|
||||||
|
const std::string& tag,
|
||||||
|
const std::string& mapping_key);
|
||||||
|
|
||||||
|
static commodity_t * find_or_create(const commodity_t& comm,
|
||||||
|
const amount_t& price,
|
||||||
|
const std::time_t date,
|
||||||
|
const std::string& tag);
|
||||||
|
|
||||||
|
friend class amount_t;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline std::ostream& operator<<(std::ostream& out, const commodity_t& comm) {
|
inline std::ostream& operator<<(std::ostream& out, const commodity_t& comm) {
|
||||||
|
|
|
||||||
|
|
@ -101,7 +101,7 @@ class balance_t
|
||||||
if (i != amounts.end()) {
|
if (i != amounts.end()) {
|
||||||
(*i).second -= amt;
|
(*i).second -= amt;
|
||||||
if ((*i).second.realzero())
|
if ((*i).second.realzero())
|
||||||
amounts.erase(&amt.commodity());
|
amounts.erase(i);
|
||||||
}
|
}
|
||||||
else if (! amt.realzero()) {
|
else if (! amt.realzero()) {
|
||||||
amounts.insert(amounts_pair(&amt.commodity(), - amt));
|
amounts.insert(amounts_pair(&amt.commodity(), - amt));
|
||||||
|
|
|
||||||
59
journal.cc
59
journal.cc
|
|
@ -36,11 +36,15 @@ std::time_t transaction_t::effective_date() const
|
||||||
|
|
||||||
bool transaction_t::valid() const
|
bool transaction_t::valid() const
|
||||||
{
|
{
|
||||||
if (! entry)
|
if (! entry) {
|
||||||
|
DEBUG_PRINT("ledger.validate", "transaction_t: ! entry");
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (state != UNCLEARED && state != CLEARED && state != PENDING)
|
if (state != UNCLEARED && state != CLEARED && state != PENDING) {
|
||||||
|
DEBUG_PRINT("ledger.validate", "transaction_t: state is bad");
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool found = false;
|
bool found = false;
|
||||||
for (transactions_list::const_iterator i = entry->transactions.begin();
|
for (transactions_list::const_iterator i = entry->transactions.begin();
|
||||||
|
|
@ -50,20 +54,30 @@ bool transaction_t::valid() const
|
||||||
found = true;
|
found = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (! found)
|
if (! found) {
|
||||||
|
DEBUG_PRINT("ledger.validate", "transaction_t: ! found");
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (! account)
|
if (! account) {
|
||||||
|
DEBUG_PRINT("ledger.validate", "transaction_t: ! account");
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (! amount.valid())
|
if (! amount.valid()) {
|
||||||
|
DEBUG_PRINT("ledger.validate", "transaction_t: ! amount.valid()");
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (cost && ! cost->valid())
|
if (cost && ! cost->valid()) {
|
||||||
|
DEBUG_PRINT("ledger.validate", "transaction_t: cost && ! cost->valid()");
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (flags & ~0x001f)
|
if (flags & ~0x001f) {
|
||||||
|
DEBUG_PRINT("ledger.validate", "transaction_t: flags are bad");
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -158,7 +172,8 @@ bool entry_base_t::finalize()
|
||||||
|
|
||||||
entry_t * entry = dynamic_cast<entry_t *>(this);
|
entry_t * entry = dynamic_cast<entry_t *>(this);
|
||||||
|
|
||||||
if (! (*x)->amount.commodity().annotated)
|
if ((*x)->amount.commodity() &&
|
||||||
|
! (*x)->amount.commodity().annotated)
|
||||||
(*x)->amount.annotate_commodity(abs(per_unit_cost),
|
(*x)->amount.annotate_commodity(abs(per_unit_cost),
|
||||||
entry ? entry->actual_date() : 0,
|
entry ? entry->actual_date() : 0,
|
||||||
entry ? entry->code : "");
|
entry ? entry->code : "");
|
||||||
|
|
@ -271,14 +286,18 @@ void entry_t::add_transaction(transaction_t * xact)
|
||||||
|
|
||||||
bool entry_t::valid() const
|
bool entry_t::valid() const
|
||||||
{
|
{
|
||||||
if (! _date || ! journal)
|
if (! _date || ! journal) {
|
||||||
|
DEBUG_PRINT("ledger.validate", "entry_t: ! _date || ! journal");
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
for (transactions_list::const_iterator i = transactions.begin();
|
for (transactions_list::const_iterator i = transactions.begin();
|
||||||
i != transactions.end();
|
i != transactions.end();
|
||||||
i++)
|
i++)
|
||||||
if ((*i)->entry != this || ! (*i)->valid())
|
if ((*i)->entry != this || ! (*i)->valid()) {
|
||||||
|
DEBUG_PRINT("ledger.validate", "entry_t: transaction not valid");
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -434,14 +453,18 @@ std::ostream& operator<<(std::ostream& out, const account_t& account)
|
||||||
|
|
||||||
bool account_t::valid() const
|
bool account_t::valid() const
|
||||||
{
|
{
|
||||||
if (depth > 256 || ! journal)
|
if (depth > 256 || ! journal) {
|
||||||
|
DEBUG_PRINT("ledger.validate", "account_t: depth > 256 || ! journal");
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
for (accounts_map::const_iterator i = accounts.begin();
|
for (accounts_map::const_iterator i = accounts.begin();
|
||||||
i != accounts.end();
|
i != accounts.end();
|
||||||
i++)
|
i++)
|
||||||
if (! (*i).second->valid())
|
if (! (*i).second->valid()) {
|
||||||
|
DEBUG_PRINT("ledger.validate", "account_t: child not valid");
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -528,20 +551,26 @@ bool journal_t::remove_entry(entry_t * entry)
|
||||||
|
|
||||||
bool journal_t::valid() const
|
bool journal_t::valid() const
|
||||||
{
|
{
|
||||||
if (! master->valid())
|
if (! master->valid()) {
|
||||||
|
DEBUG_PRINT("ledger.validate", "journal_t: master not valid");
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
for (entries_list::const_iterator i = entries.begin();
|
for (entries_list::const_iterator i = entries.begin();
|
||||||
i != entries.end();
|
i != entries.end();
|
||||||
i++)
|
i++)
|
||||||
if (! (*i)->valid())
|
if (! (*i)->valid()) {
|
||||||
|
DEBUG_PRINT("ledger.validate", "journal_t: entry not valid");
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
for (commodities_map::const_iterator i = commodity_t::commodities.begin();
|
for (commodities_map::const_iterator i = commodity_t::commodities.begin();
|
||||||
i != commodity_t::commodities.end();
|
i != commodity_t::commodities.end();
|
||||||
i++)
|
i++)
|
||||||
if (! (*i).second->valid())
|
if (! (*i).second->valid()) {
|
||||||
|
DEBUG_PRINT("ledger.validate", "journal_t: commodity not valid");
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
23
textual.cc
23
textual.cc
|
|
@ -229,16 +229,19 @@ transaction_t * parse_transaction(char * line, account_t * account,
|
||||||
else
|
else
|
||||||
per_unit_cost /= xact->amount;
|
per_unit_cost /= xact->amount;
|
||||||
|
|
||||||
if (! xact->amount.commodity().annotated) {
|
if (xact->amount.commodity()) {
|
||||||
xact->amount.annotate_commodity(per_unit_cost,
|
if (! xact->amount.commodity().annotated) {
|
||||||
xact->entry->actual_date(),
|
xact->amount.annotate_commodity(per_unit_cost,
|
||||||
xact->entry->code);
|
xact->entry->actual_date(),
|
||||||
} else {
|
xact->entry->code);
|
||||||
annotated_commodity_t& ann(static_cast<annotated_commodity_t&>
|
} else {
|
||||||
(xact->amount.commodity()));
|
annotated_commodity_t& ann(static_cast<annotated_commodity_t&>
|
||||||
xact->amount.annotate_commodity(! ann.price ? per_unit_cost : amount_t(),
|
(xact->amount.commodity()));
|
||||||
! ann.date ? xact->entry->actual_date() : 0,
|
xact->amount.annotate_commodity
|
||||||
ann.tag.empty() ? xact->entry->code : "");
|
(! ann.price ? per_unit_cost : amount_t(),
|
||||||
|
! ann.date ? xact->entry->actual_date() : 0,
|
||||||
|
ann.tag.empty() ? xact->entry->code : "");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUG_PRINT("ledger.textual.parse", "line " << linenum << ": " <<
|
DEBUG_PRINT("ledger.textual.parse", "line " << linenum << ": " <<
|
||||||
|
|
|
||||||
10
valexpr.cc
10
valexpr.cc
|
|
@ -629,7 +629,10 @@ void value_expr_t::compute(value_t& result, const details_t& details,
|
||||||
|
|
||||||
case O_NOT:
|
case O_NOT:
|
||||||
left->compute(result, details, context);
|
left->compute(result, details, context);
|
||||||
result.negate();
|
if (result.strip_annotations())
|
||||||
|
result = false;
|
||||||
|
else
|
||||||
|
result = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case O_QUES: {
|
case O_QUES: {
|
||||||
|
|
@ -637,7 +640,7 @@ void value_expr_t::compute(value_t& result, const details_t& details,
|
||||||
assert(right);
|
assert(right);
|
||||||
assert(right->kind == O_COL);
|
assert(right->kind == O_COL);
|
||||||
left->compute(result, details, context);
|
left->compute(result, details, context);
|
||||||
if (result)
|
if (result.strip_annotations())
|
||||||
right->left->compute(result, details, context);
|
right->left->compute(result, details, context);
|
||||||
else
|
else
|
||||||
right->right->compute(result, details, context);
|
right->right->compute(result, details, context);
|
||||||
|
|
@ -648,6 +651,7 @@ void value_expr_t::compute(value_t& result, const details_t& details,
|
||||||
assert(left);
|
assert(left);
|
||||||
assert(right);
|
assert(right);
|
||||||
left->compute(result, details, context);
|
left->compute(result, details, context);
|
||||||
|
result = result.strip_annotations();
|
||||||
if (result)
|
if (result)
|
||||||
right->compute(result, details, context);
|
right->compute(result, details, context);
|
||||||
break;
|
break;
|
||||||
|
|
@ -656,7 +660,7 @@ void value_expr_t::compute(value_t& result, const details_t& details,
|
||||||
assert(left);
|
assert(left);
|
||||||
assert(right);
|
assert(right);
|
||||||
left->compute(result, details, context);
|
left->compute(result, details, context);
|
||||||
if (! result)
|
if (! result.strip_annotations())
|
||||||
right->compute(result, details, context);
|
right->compute(result, details, context);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -491,7 +491,8 @@ class item_predicate
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator()(const T& item) const {
|
bool operator()(const T& item) const {
|
||||||
return ! predicate || predicate->compute(details_t(item));
|
return (! predicate ||
|
||||||
|
predicate->compute(details_t(item)).strip_annotations());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
4
value.cc
4
value.cc
|
|
@ -1233,11 +1233,9 @@ value_t value_t::strip_annotations(const bool keep_price,
|
||||||
{
|
{
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case BOOLEAN:
|
case BOOLEAN:
|
||||||
throw new value_error("Cannot strip commodity annotations from a boolean");
|
|
||||||
case INTEGER:
|
case INTEGER:
|
||||||
return *this;
|
|
||||||
case DATETIME:
|
case DATETIME:
|
||||||
throw new value_error("Cannot strip commodity annotations from a date/time");
|
return *this;
|
||||||
|
|
||||||
case AMOUNT:
|
case AMOUNT:
|
||||||
return ((amount_t *) data)->strip_annotations
|
return ((amount_t *) data)->strip_annotations
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue