summaryrefslogtreecommitdiff
path: root/src/amount.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/amount.cc')
-rw-r--r--src/amount.cc858
1 files changed, 386 insertions, 472 deletions
diff --git a/src/amount.cc b/src/amount.cc
index 7b8b1a91..348fda64 100644
--- a/src/amount.cc
+++ b/src/amount.cc
@@ -45,12 +45,12 @@
namespace ledger {
-bool do_cleanup = true;
+bool amount_t::keep_base = false;
bool amount_t::keep_price = false;
bool amount_t::keep_date = false;
bool amount_t::keep_tag = false;
-bool amount_t::keep_base = false;
+
bool amount_t::full_strings = false;
#define BIGINT_BULK_ALLOC 0x0001
@@ -99,7 +99,7 @@ static amount_t::bigint_t * true_value = NULL;
inline amount_t::bigint_t::~bigint_t() {
TRACE_DTOR(bigint_t);
- assert(ref == 0 || (! do_cleanup && this == true_value));
+ assert(ref == 0 || this == true_value);
mpz_clear(val);
}
@@ -164,18 +164,6 @@ void amount_t::shutdown()
true_value = NULL;
}
-void amount_t::_release()
-{
- DEBUG("amounts.refs", quantity << " ref--, now " << (quantity->ref - 1));
-
- if (--quantity->ref == 0) {
- if (! (quantity->flags & BIGINT_BULK_ALLOC))
- checked_delete(quantity);
- else
- quantity->~bigint_t();
- }
-}
-
void amount_t::_init()
{
if (! quantity) {
@@ -187,15 +175,6 @@ void amount_t::_init()
}
}
-void amount_t::_dup()
-{
- if (quantity->ref > 1) {
- bigint_t * q = new bigint_t(*quantity);
- _release();
- quantity = q;
- }
-}
-
void amount_t::_copy(const amount_t& amt)
{
if (quantity != amt.quantity) {
@@ -216,6 +195,15 @@ void amount_t::_copy(const amount_t& amt)
commodity_ = amt.commodity_;
}
+void amount_t::_dup()
+{
+ if (quantity->ref > 1) {
+ bigint_t * q = new bigint_t(*quantity);
+ _release();
+ quantity = q;
+ }
+}
+
void amount_t::_resize(precision_t prec)
{
assert(prec < 256);
@@ -247,31 +235,19 @@ void amount_t::_clear()
}
}
-
-amount_t::amount_t(const long val)
+void amount_t::_release()
{
- TRACE_CTOR(amount_t, "const long");
- if (val != 0) {
- quantity = new bigint_t;
- mpz_set_si(MPZ(quantity), val);
- } else {
- quantity = NULL;
- }
- commodity_ = NULL;
-}
+ DEBUG("amounts.refs", quantity << " ref--, now " << (quantity->ref - 1));
-amount_t::amount_t(const unsigned long val)
-{
- TRACE_CTOR(amount_t, "const unsigned long");
- if (val != 0) {
- quantity = new bigint_t;
- mpz_set_ui(MPZ(quantity), val);
- } else {
- quantity = NULL;
+ if (--quantity->ref == 0) {
+ if (! (quantity->flags & BIGINT_BULK_ALLOC))
+ checked_delete(quantity);
+ else
+ quantity->~bigint_t();
}
- commodity_ = NULL;
}
+
namespace {
amount_t::bigint_t::precision_t convert_double(mpz_t dest, double val)
{
@@ -366,6 +342,34 @@ amount_t::amount_t(const double val)
commodity_ = NULL;
}
+amount_t::amount_t(const unsigned long val)
+{
+ TRACE_CTOR(amount_t, "const unsigned long");
+ quantity = new bigint_t;
+ mpz_set_ui(MPZ(quantity), val);
+ commodity_ = NULL;
+}
+
+amount_t::amount_t(const long val)
+{
+ TRACE_CTOR(amount_t, "const long");
+ quantity = new bigint_t;
+ mpz_set_si(MPZ(quantity), val);
+ commodity_ = NULL;
+}
+
+
+amount_t& amount_t::operator=(const amount_t& amt)
+{
+ if (this != &amt) {
+ if (amt.quantity)
+ _copy(amt);
+ else if (quantity)
+ _clear();
+ }
+ return *this;
+}
+
int amount_t::compare(const amount_t& amt) const
{
@@ -398,18 +402,6 @@ int amount_t::compare(const amount_t& amt) const
}
-// assignment operator
-amount_t& amount_t::operator=(const amount_t& amt)
-{
- if (this != &amt) {
- if (amt.quantity)
- _copy(amt);
- else if (quantity)
- _clear();
- }
- return *this;
-}
-
amount_t& amount_t::operator+=(const amount_t& amt)
{
if (commodity() != amt.commodity())
@@ -622,79 +614,13 @@ amount_t& amount_t::operator/=(const amount_t& amt)
return *this;
}
-// unary negation
-void amount_t::in_place_negate()
+
+amount_t& amount_t::in_place_negate()
{
if (quantity) {
_dup();
mpz_neg(MPZ(quantity), MPZ(quantity));
}
-}
-
-int amount_t::sign() const
-{
- return quantity ? mpz_sgn(MPZ(quantity)) : 0;
-}
-
-bool amount_t::zero() const
-{
- if (! quantity)
- return true;
-
- if (has_commodity()) {
- if (quantity->prec <= commodity().precision())
- return realzero();
- else
- return round(commodity().precision()).sign() == 0;
- }
- return realzero();
-}
-
-long amount_t::to_long() const
-{
- if (! quantity)
- return 0;
-
- mpz_set(temp, MPZ(quantity));
- mpz_ui_pow_ui(divisor, 10, quantity->prec);
- mpz_tdiv_q(temp, temp, divisor);
-
- return mpz_get_si(temp);
-}
-
-double amount_t::to_double() const
-{
- if (! quantity)
- return 0.0;
-
- mpz_t remainder;
- mpz_init(remainder);
-
- mpz_set(temp, MPZ(quantity));
- mpz_ui_pow_ui(divisor, 10, quantity->prec);
- mpz_tdiv_qr(temp, remainder, temp, divisor);
-
- char * quotient_s = mpz_get_str(NULL, 10, temp);
- char * remainder_s = mpz_get_str(NULL, 10, remainder);
-
- std::ostringstream num;
- num << quotient_s << '.' << remainder_s;
-
- std::free(quotient_s);
- std::free(remainder_s);
-
- mpz_clear(remainder);
-
- return lexical_cast<double>(num.str());
-}
-
-amount_t amount_t::value(const moment_t& moment) const
-{
- if (quantity) {
- amount_t amt(commodity().value(moment));
- if (! amt.realzero())
- return (amt * number()).round();
- }
return *this;
}
@@ -739,281 +665,205 @@ amount_t amount_t::unround() const
return t;
}
-void amount_t::print_quantity(std::ostream& out) const
+amount_t& amount_t::in_place_reduce()
{
- if (! quantity) {
- out << "0";
- return;
- }
-
- mpz_t quotient;
- mpz_t rquotient;
- mpz_t remainder;
-
- mpz_init(quotient);
- mpz_init(rquotient);
- mpz_init(remainder);
-
- bool negative = false;
-
- // Ensure the value is rounded to the commodity's precision before
- // outputting it. NOTE: `rquotient' is used here as a temp variable!
-
- commodity_t& comm(commodity());
- bigint_t::precision_t precision;
-
- if (! comm || quantity->flags & BIGINT_KEEP_PREC) {
- mpz_ui_pow_ui(divisor, 10, quantity->prec);
- mpz_tdiv_qr(quotient, remainder, MPZ(quantity), divisor);
- precision = quantity->prec;
- }
- else if (comm.precision() < quantity->prec) {
- mpz_round(rquotient, MPZ(quantity), quantity->prec, comm.precision());
- mpz_ui_pow_ui(divisor, 10, comm.precision());
- mpz_tdiv_qr(quotient, remainder, rquotient, divisor);
- precision = comm.precision();
- }
- else if (comm.precision() > quantity->prec) {
- mpz_ui_pow_ui(divisor, 10, comm.precision() - quantity->prec);
- mpz_mul(rquotient, MPZ(quantity), divisor);
- mpz_ui_pow_ui(divisor, 10, comm.precision());
- mpz_tdiv_qr(quotient, remainder, rquotient, divisor);
- precision = comm.precision();
- }
- else if (quantity->prec) {
- mpz_ui_pow_ui(divisor, 10, quantity->prec);
- mpz_tdiv_qr(quotient, remainder, MPZ(quantity), divisor);
- precision = quantity->prec;
- }
- else {
- mpz_set(quotient, MPZ(quantity));
- mpz_set_ui(remainder, 0);
- precision = 0;
+ while (commodity_ && commodity().smaller()) {
+ *this *= commodity().smaller()->number();
+ commodity_ = commodity().smaller()->commodity_;
}
+ return *this;
+}
- if (mpz_sgn(quotient) < 0 || mpz_sgn(remainder) < 0) {
- negative = true;
-
- mpz_abs(quotient, quotient);
- mpz_abs(remainder, remainder);
+amount_t& amount_t::in_place_unreduce()
+{
+ while (commodity_ && commodity().larger()) {
+ *this /= commodity().larger()->number();
+ commodity_ = commodity().larger()->commodity_;
+ if (abs() < amount_t(1.0))
+ break;
}
- mpz_set(rquotient, remainder);
+ return *this;
+}
- if (mpz_sgn(quotient) == 0 && mpz_sgn(rquotient) == 0) {
- out << "0";
- return;
+amount_t amount_t::value(const moment_t& moment) const
+{
+ if (quantity) {
+ amount_t amt(commodity().value(moment));
+ if (! amt.realzero())
+ return (amt * number()).round();
}
+ return *this;
+}
- if (negative)
- out << "-";
- if (mpz_sgn(quotient) == 0) {
- out << '0';
- } else {
- char * p = mpz_get_str(NULL, 10, quotient);
- out << p;
- std::free(p);
- }
-
- if (precision) {
- out << '.';
+int amount_t::sign() const
+{
+ return quantity ? mpz_sgn(MPZ(quantity)) : 0;
+}
- out.width(precision);
- out.fill('0');
+bool amount_t::zero() const
+{
+ if (! quantity)
+ return true;
- char * p = mpz_get_str(NULL, 10, rquotient);
- out << p;
- std::free(p);
+ if (has_commodity()) {
+ if (quantity->prec <= commodity().precision())
+ return realzero();
+ else
+ return round(commodity().precision()).sign() == 0;
}
-
- mpz_clear(quotient);
- mpz_clear(rquotient);
- mpz_clear(remainder);
+ return realzero();
}
-void amount_t::print(std::ostream& _out, bool omit_commodity,
- bool full_precision) const
-{
- amount_t base(*this);
- if (! amount_t::keep_base && commodity().larger()) {
- amount_t last(*this);
- while (last.commodity().larger()) {
- last /= last.commodity().larger()->number();
- last.commodity_ = last.commodity().larger()->commodity_;
- if (last.abs() < amount_t(1.0))
- break;
- base = last.round();
- }
- }
- std::ostringstream out;
+double amount_t::to_double() const
+{
+ if (! quantity)
+ return 0.0;
- mpz_t quotient;
- mpz_t rquotient;
mpz_t remainder;
-
- mpz_init(quotient);
- mpz_init(rquotient);
mpz_init(remainder);
- bool negative = false;
+ mpz_set(temp, MPZ(quantity));
+ mpz_ui_pow_ui(divisor, 10, quantity->prec);
+ mpz_tdiv_qr(temp, remainder, temp, divisor);
- // Ensure the value is rounded to the commodity's precision before
- // outputting it. NOTE: `rquotient' is used here as a temp variable!
+ char * quotient_s = mpz_get_str(NULL, 10, temp);
+ char * remainder_s = mpz_get_str(NULL, 10, remainder);
- commodity_t& comm(base.commodity());
- bigint_t::precision_t precision = 0;
+ std::ostringstream num;
+ num << quotient_s << '.' << remainder_s;
- if (quantity) {
- if (! comm || full_precision || base.quantity->flags & BIGINT_KEEP_PREC) {
- mpz_ui_pow_ui(divisor, 10, base.quantity->prec);
- mpz_tdiv_qr(quotient, remainder, MPZ(base.quantity), divisor);
- precision = base.quantity->prec;
- }
- else if (comm.precision() < base.quantity->prec) {
- mpz_round(rquotient, MPZ(base.quantity), base.quantity->prec,
- comm.precision());
- mpz_ui_pow_ui(divisor, 10, comm.precision());
- mpz_tdiv_qr(quotient, remainder, rquotient, divisor);
- precision = comm.precision();
- }
- else if (comm.precision() > base.quantity->prec) {
- mpz_ui_pow_ui(divisor, 10, comm.precision() - base.quantity->prec);
- mpz_mul(rquotient, MPZ(base.quantity), divisor);
- mpz_ui_pow_ui(divisor, 10, comm.precision());
- mpz_tdiv_qr(quotient, remainder, rquotient, divisor);
- precision = comm.precision();
- }
- else if (base.quantity->prec) {
- mpz_ui_pow_ui(divisor, 10, base.quantity->prec);
- mpz_tdiv_qr(quotient, remainder, MPZ(base.quantity), divisor);
- precision = base.quantity->prec;
- }
- else {
- mpz_set(quotient, MPZ(base.quantity));
- mpz_set_ui(remainder, 0);
- precision = 0;
- }
+ std::free(quotient_s);
+ std::free(remainder_s);
- if (mpz_sgn(quotient) < 0 || mpz_sgn(remainder) < 0) {
- negative = true;
+ mpz_clear(remainder);
- mpz_abs(quotient, quotient);
- mpz_abs(remainder, remainder);
- }
- mpz_set(rquotient, remainder);
- }
+ return lexical_cast<double>(num.str());
+}
- if (! omit_commodity && ! (comm.flags() & COMMODITY_STYLE_SUFFIXED)) {
- comm.write(out);
+long amount_t::to_long() const
+{
+ if (! quantity)
+ return 0;
- if (comm.flags() & COMMODITY_STYLE_SEPARATED)
- out << " ";
- }
+ mpz_set(temp, MPZ(quantity));
+ mpz_ui_pow_ui(divisor, 10, quantity->prec);
+ mpz_tdiv_q(temp, temp, divisor);
- if (negative)
- out << "-";
+ return mpz_get_si(temp);
+}
- if (! quantity || mpz_sgn(quotient) == 0) {
- out << '0';
- }
- else if (! (comm.flags() & COMMODITY_STYLE_THOUSANDS)) {
- char * p = mpz_get_str(NULL, 10, quotient);
- out << p;
- std::free(p);
- }
- else {
- std::list<string> strs;
- char buf[4];
- for (int powers = 0; true; powers += 3) {
- if (powers > 0) {
- mpz_ui_pow_ui(divisor, 10, powers);
- mpz_tdiv_q(temp, quotient, divisor);
- if (mpz_sgn(temp) == 0)
- break;
- mpz_tdiv_r_ui(temp, temp, 1000);
- } else {
- mpz_tdiv_r_ui(temp, quotient, 1000);
- }
- mpz_get_str(buf, 10, temp);
- strs.push_back(buf);
- }
+void amount_t::annotate_commodity(const optional<amount_t>& tprice,
+ const optional<moment_t>& tdate,
+ const optional<string>& ttag)
+{
+ const commodity_t * this_base;
+ annotated_commodity_t * this_ann = NULL;
- bool printed = false;
+ if (commodity().annotated) {
+ this_ann = &static_cast<annotated_commodity_t&>(commodity());
+ this_base = this_ann->ptr;
+ } else {
+ this_base = &commodity();
+ }
+ assert(this_base);
- for (std::list<string>::reverse_iterator i = strs.rbegin();
- i != strs.rend();
- i++) {
- if (printed) {
- out << (comm.flags() & COMMODITY_STYLE_EUROPEAN ? '.' : ',');
- out.width(3);
- out.fill('0');
- }
- out << *i;
+ DEBUG("amounts.commodities", "Annotating commodity for amount "
+ << *this << std::endl
+ << " price " << (tprice ? tprice->to_string() : "NONE") << " "
+ << " date " << (tdate ? *tdate : moment_t()) << " "
+ << " ttag " << (ttag ? *ttag : "NONE"));
- printed = true;
- }
- }
+ if (commodity_t * ann_comm =
+ annotated_commodity_t::find_or_create
+ (*this_base,
+ ! tprice && this_ann ? this_ann->price : tprice,
+ ! tdate && this_ann ? this_ann->date : tdate,
+ ! ttag && this_ann ? this_ann->tag : ttag))
+ set_commodity(*ann_comm);
- if (quantity && precision) {
- std::ostringstream final;
- final.width(precision);
- final.fill('0');
- char * p = mpz_get_str(NULL, 10, rquotient);
- final << p;
- std::free(p);
+ DEBUG("amounts.commodities", " Annotated amount is " << *this);
+}
- const string& str(final.str());
- int i, len = str.length();
- const char * q = str.c_str();
- for (i = len; i > 0; i--)
- if (q[i - 1] != '0')
- break;
+amount_t amount_t::strip_annotations(const bool _keep_price,
+ const bool _keep_date,
+ const bool _keep_tag) const
+{
+ if (! commodity().annotated ||
+ (_keep_price && _keep_date && _keep_tag))
+ return *this;
- string ender;
- if (i == len)
- ender = str;
- else if (i < comm.precision())
- ender = string(str, 0, comm.precision());
- else
- ender = string(str, 0, i);
+ DEBUG("amounts.commodities", "Reducing commodity for amount "
+ << *this << std::endl
+ << " keep price " << _keep_price << " "
+ << " keep date " << _keep_date << " "
+ << " keep tag " << _keep_tag);
- if (! ender.empty()) {
- out << ((comm.flags() & COMMODITY_STYLE_EUROPEAN) ? ',' : '.');
- out << ender;
- }
- }
+ annotated_commodity_t&
+ ann_comm(static_cast<annotated_commodity_t&>(commodity()));
+ assert(ann_comm.base);
- if (! omit_commodity && comm.flags() & COMMODITY_STYLE_SUFFIXED) {
- if (comm.flags() & COMMODITY_STYLE_SEPARATED)
- out << " ";
+ commodity_t * new_comm;
- comm.write(out);
+ if ((_keep_price && ann_comm.price) ||
+ (_keep_date && ann_comm.date) ||
+ (_keep_tag && ann_comm.tag))
+ {
+ new_comm = annotated_commodity_t::find_or_create
+ (*ann_comm.ptr,
+ _keep_price ? ann_comm.price : optional<amount_t>(),
+ _keep_date ? ann_comm.date : optional<moment_t>(),
+ _keep_tag ? ann_comm.tag : optional<string>());
+ } else {
+ new_comm = commodity_t::find_or_create(ann_comm.base_symbol());
}
+ assert(new_comm);
- mpz_clear(quotient);
- mpz_clear(rquotient);
- mpz_clear(remainder);
+ amount_t t(*this);
+ t.set_commodity(*new_comm);
+ DEBUG("amounts.commodities", " Reduced amount is " << t);
- // If there are any annotations associated with this commodity,
- // output them now.
+ return t;
+}
- if (! omit_commodity && comm.annotated) {
- annotated_commodity_t& ann(static_cast<annotated_commodity_t&>(comm));
- assert(&*ann.price != this);
- ann.write_annotations(out);
+optional<amount_t> amount_t::price() const
+{
+ if (commodity_ && commodity_->annotated &&
+ ((annotated_commodity_t *)commodity_)->price) {
+ amount_t t(*((annotated_commodity_t *)commodity_)->price);
+ t *= number();
+ DEBUG("amounts.commodities",
+ "Returning price of " << *this << " = " << t);
+ return t;
}
+ return optional<amount_t>();
+}
- // Things are output to a string first, so that if anyone has
- // specified a width or fill for _out, it will be applied to the
- // entire amount string, and not just the first part.
-
- _out << out.str();
+optional<moment_t> amount_t::date() const
+{
+ if (commodity_ && commodity_->annotated) {
+ DEBUG("amounts.commodities",
+ "Returning date of " << *this << " = "
+ << ((annotated_commodity_t *)commodity_)->date);
+ return ((annotated_commodity_t *)commodity_)->date;
+ }
+ return optional<moment_t>();
+}
- return;
+optional<string> amount_t::tag() const
+{
+ if (commodity_ && commodity_->annotated) {
+ DEBUG("amounts.commodities",
+ "Returning tag of " << *this << " = "
+ << ((annotated_commodity_t *)commodity_)->tag);
+ return ((annotated_commodity_t *)commodity_)->tag;
+ }
+ return optional<string>();
}
+
static void parse_quantity(std::istream& in, string& value)
{
char buf[256];
@@ -1287,16 +1137,8 @@ void amount_t::parse(std::istream& in, uint8_t flags)
in_place_reduce();
}
-void amount_t::in_place_reduce()
-{
- while (commodity_ && commodity().smaller()) {
- *this *= commodity().smaller()->number();
- commodity_ = commodity().smaller()->commodity_;
- }
-}
-
-void parse_conversion(const string& larger_str,
- const string& smaller_str)
+void amount_t::parse_conversion(const string& larger_str,
+ const string& smaller_str)
{
amount_t larger, smaller;
@@ -1314,6 +1156,186 @@ void parse_conversion(const string& larger_str,
smaller.commodity().set_larger(larger);
}
+
+void amount_t::print(std::ostream& _out, bool omit_commodity,
+ bool full_precision) const
+{
+ amount_t base(*this);
+ if (! amount_t::keep_base)
+ base.in_place_unreduce();
+
+ std::ostringstream out;
+
+ mpz_t quotient;
+ mpz_t rquotient;
+ mpz_t remainder;
+
+ mpz_init(quotient);
+ mpz_init(rquotient);
+ mpz_init(remainder);
+
+ bool negative = false;
+
+ // Ensure the value is rounded to the commodity's precision before
+ // outputting it. NOTE: `rquotient' is used here as a temp variable!
+
+ commodity_t& comm(base.commodity());
+ bigint_t::precision_t precision = 0;
+
+ if (quantity) {
+ if (! comm || full_precision || base.quantity->flags & BIGINT_KEEP_PREC) {
+ mpz_ui_pow_ui(divisor, 10, base.quantity->prec);
+ mpz_tdiv_qr(quotient, remainder, MPZ(base.quantity), divisor);
+ precision = base.quantity->prec;
+ }
+ else if (comm.precision() < base.quantity->prec) {
+ mpz_round(rquotient, MPZ(base.quantity), base.quantity->prec,
+ comm.precision());
+ mpz_ui_pow_ui(divisor, 10, comm.precision());
+ mpz_tdiv_qr(quotient, remainder, rquotient, divisor);
+ precision = comm.precision();
+ }
+ else if (comm.precision() > base.quantity->prec) {
+ mpz_ui_pow_ui(divisor, 10, comm.precision() - base.quantity->prec);
+ mpz_mul(rquotient, MPZ(base.quantity), divisor);
+ mpz_ui_pow_ui(divisor, 10, comm.precision());
+ mpz_tdiv_qr(quotient, remainder, rquotient, divisor);
+ precision = comm.precision();
+ }
+ else if (base.quantity->prec) {
+ mpz_ui_pow_ui(divisor, 10, base.quantity->prec);
+ mpz_tdiv_qr(quotient, remainder, MPZ(base.quantity), divisor);
+ precision = base.quantity->prec;
+ }
+ else {
+ mpz_set(quotient, MPZ(base.quantity));
+ mpz_set_ui(remainder, 0);
+ precision = 0;
+ }
+
+ if (mpz_sgn(quotient) < 0 || mpz_sgn(remainder) < 0) {
+ negative = true;
+
+ mpz_abs(quotient, quotient);
+ mpz_abs(remainder, remainder);
+ }
+ mpz_set(rquotient, remainder);
+ }
+
+ if (! omit_commodity && ! (comm.flags() & COMMODITY_STYLE_SUFFIXED)) {
+ comm.write(out);
+
+ if (comm.flags() & COMMODITY_STYLE_SEPARATED)
+ out << " ";
+ }
+
+ if (negative)
+ out << "-";
+
+ if (! quantity || mpz_sgn(quotient) == 0) {
+ out << '0';
+ }
+ else if (omit_commodity || ! (comm.flags() & COMMODITY_STYLE_THOUSANDS)) {
+ char * p = mpz_get_str(NULL, 10, quotient);
+ out << p;
+ std::free(p);
+ }
+ else {
+ std::list<string> strs;
+ char buf[4];
+
+ for (int powers = 0; true; powers += 3) {
+ if (powers > 0) {
+ mpz_ui_pow_ui(divisor, 10, powers);
+ mpz_tdiv_q(temp, quotient, divisor);
+ if (mpz_sgn(temp) == 0)
+ break;
+ mpz_tdiv_r_ui(temp, temp, 1000);
+ } else {
+ mpz_tdiv_r_ui(temp, quotient, 1000);
+ }
+ mpz_get_str(buf, 10, temp);
+ strs.push_back(buf);
+ }
+
+ bool printed = false;
+
+ for (std::list<string>::reverse_iterator i = strs.rbegin();
+ i != strs.rend();
+ i++) {
+ if (printed) {
+ out << (comm.flags() & COMMODITY_STYLE_EUROPEAN ? '.' : ',');
+ out.width(3);
+ out.fill('0');
+ }
+ out << *i;
+
+ printed = true;
+ }
+ }
+
+ if (quantity && precision) {
+ std::ostringstream final;
+ final.width(precision);
+ final.fill('0');
+ char * p = mpz_get_str(NULL, 10, rquotient);
+ final << p;
+ std::free(p);
+
+ const string& str(final.str());
+ int i, len = str.length();
+ const char * q = str.c_str();
+ for (i = len; i > 0; i--)
+ if (q[i - 1] != '0')
+ break;
+
+ string ender;
+ if (i == len)
+ ender = str;
+ else if (i < comm.precision())
+ ender = string(str, 0, comm.precision());
+ else
+ ender = string(str, 0, i);
+
+ if (! ender.empty()) {
+ if (omit_commodity)
+ out << '.';
+ else
+ out << ((comm.flags() & COMMODITY_STYLE_EUROPEAN) ? ',' : '.');
+ out << ender;
+ }
+ }
+
+ if (! omit_commodity && comm.flags() & COMMODITY_STYLE_SUFFIXED) {
+ if (comm.flags() & COMMODITY_STYLE_SEPARATED)
+ out << " ";
+
+ comm.write(out);
+ }
+
+ mpz_clear(quotient);
+ mpz_clear(rquotient);
+ mpz_clear(remainder);
+
+ // If there are any annotations associated with this commodity,
+ // output them now.
+
+ if (! omit_commodity && comm.annotated) {
+ annotated_commodity_t& ann(static_cast<annotated_commodity_t&>(comm));
+ assert(&*ann.price != this);
+ ann.write_annotations(out);
+ }
+
+ // Things are output to a string first, so that if anyone has
+ // specified a width or fill for _out, it will be applied to the
+ // entire amount string, and not just the first part.
+
+ _out << out.str();
+
+ return;
+}
+
+
void amount_t::read(std::istream& in)
{
commodity_t::ident_t ident;
@@ -1352,7 +1374,6 @@ void amount_t::write(std::ostream& out) const
write_quantity(out);
}
-
#ifndef THREADSAFE
static char * bigints;
static char * bigints_next;
@@ -1476,6 +1497,7 @@ void amount_t::write_quantity(std::ostream& out) const
}
}
+
bool amount_t::valid() const
{
if (quantity) {
@@ -1491,112 +1513,4 @@ bool amount_t::valid() const
return true;
}
-void amount_t::annotate_commodity(const optional<amount_t>& tprice,
- const optional<moment_t>& tdate,
- const optional<string>& ttag)
-{
- const commodity_t * this_base;
- annotated_commodity_t * this_ann = NULL;
-
- if (commodity().annotated) {
- this_ann = &static_cast<annotated_commodity_t&>(commodity());
- this_base = this_ann->ptr;
- } else {
- this_base = &commodity();
- }
- assert(this_base);
-
- DEBUG("amounts.commodities", "Annotating commodity for amount "
- << *this << std::endl
- << " price " << (tprice ? tprice->to_string() : "NONE") << " "
- << " date " << (tdate ? *tdate : moment_t()) << " "
- << " ttag " << (ttag ? *ttag : "NONE"));
-
- if (commodity_t * ann_comm =
- annotated_commodity_t::find_or_create
- (*this_base,
- ! tprice && this_ann ? this_ann->price : tprice,
- ! tdate && this_ann ? this_ann->date : tdate,
- ! ttag && this_ann ? this_ann->tag : ttag))
- set_commodity(*ann_comm);
-
- DEBUG("amounts.commodities", " Annotated amount is " << *this);
-}
-
-amount_t amount_t::strip_annotations(const bool _keep_price,
- const bool _keep_date,
- const bool _keep_tag) const
-{
- if (! commodity().annotated ||
- (_keep_price && _keep_date && _keep_tag))
- return *this;
-
- DEBUG("amounts.commodities", "Reducing commodity for amount "
- << *this << std::endl
- << " keep price " << _keep_price << " "
- << " keep date " << _keep_date << " "
- << " keep tag " << _keep_tag);
-
- annotated_commodity_t&
- ann_comm(static_cast<annotated_commodity_t&>(commodity()));
- assert(ann_comm.base);
-
- commodity_t * new_comm;
-
- if ((_keep_price && ann_comm.price) ||
- (_keep_date && ann_comm.date) ||
- (_keep_tag && ann_comm.tag))
- {
- new_comm = annotated_commodity_t::find_or_create
- (*ann_comm.ptr,
- _keep_price ? ann_comm.price : optional<amount_t>(),
- _keep_date ? ann_comm.date : optional<moment_t>(),
- _keep_tag ? ann_comm.tag : optional<string>());
- } else {
- new_comm = commodity_t::find_or_create(ann_comm.base_symbol());
- }
- assert(new_comm);
-
- amount_t t(*this);
- t.set_commodity(*new_comm);
- DEBUG("amounts.commodities", " Reduced amount is " << t);
-
- return t;
-}
-
-optional<amount_t> amount_t::price() const
-{
- if (commodity_ && commodity_->annotated &&
- ((annotated_commodity_t *)commodity_)->price) {
- amount_t t(*((annotated_commodity_t *)commodity_)->price);
- t *= number();
- DEBUG("amounts.commodities",
- "Returning price of " << *this << " = " << t);
- return t;
- }
- return optional<amount_t>();
-}
-
-optional<moment_t> amount_t::date() const
-{
- if (commodity_ && commodity_->annotated) {
- DEBUG("amounts.commodities",
- "Returning date of " << *this << " = "
- << ((annotated_commodity_t *)commodity_)->date);
- return ((annotated_commodity_t *)commodity_)->date;
- }
- return optional<moment_t>();
-}
-
-optional<string> amount_t::tag() const
-{
- if (commodity_ && commodity_->annotated) {
- DEBUG("amounts.commodities",
- "Returning tag of " << *this << " = "
- << ((annotated_commodity_t *)commodity_)->tag);
- return ((annotated_commodity_t *)commodity_)->tag;
- }
- return optional<string>();
-}
-
} // namespace ledger