summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/amount.cc303
-rw-r--r--src/amount.h7
-rw-r--r--src/commodity.cc143
-rw-r--r--src/commodity.h16
4 files changed, 234 insertions, 235 deletions
diff --git a/src/amount.cc b/src/amount.cc
index aef13ba8..70d1ac4f 100644
--- a/src/amount.cc
+++ b/src/amount.cc
@@ -799,49 +799,6 @@ void amount_t::annotate_commodity(const annotation_t& details)
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 (! quantity)
- throw_(amount_error,
- "Cannot strip commodity annotations from an uninitialized amount");
-
- 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(commodity().as_annotated());
- commodity_t * new_comm;
-
- if ((_keep_price && ann_comm.details.price) ||
- (_keep_date && ann_comm.details.date) ||
- (_keep_tag && ann_comm.details.tag))
- {
- new_comm = ann_comm.parent().find_or_create
- (ann_comm.referent(),
- annotation_t(_keep_price ? ann_comm.details.price : optional<amount_t>(),
- _keep_date ? ann_comm.details.date : optional<moment_t>(),
- _keep_tag ? ann_comm.details.tag : optional<string>()));
- } else {
- new_comm = ann_comm.parent().find_or_create(ann_comm.base_symbol());
- }
- assert(new_comm);
-
- amount_t t(*this);
- t.set_commodity(*new_comm);
-
- DEBUG("amounts.commodities", " Stripped amount is " << t);
-
- return t;
-}
-
bool amount_t::commodity_annotated() const
{
if (! quantity)
@@ -867,6 +824,25 @@ annotation_t amount_t::annotation_details() const
return annotation_t();
}
+amount_t amount_t::strip_annotations(const bool _keep_price,
+ const bool _keep_date,
+ const bool _keep_tag) const
+{
+ if (! quantity)
+ throw_(amount_error,
+ "Cannot strip commodity annotations from an uninitialized amount");
+
+ if (! commodity().annotated ||
+ (_keep_price && _keep_date && _keep_tag))
+ return *this;
+
+ amount_t t(*this);
+ t.set_commodity(commodity().as_annotated().
+ strip_annotations(_keep_price, _keep_date, _keep_tag));
+ return t;
+}
+
+
namespace {
void parse_quantity(std::istream& in, string& value)
{
@@ -883,121 +859,6 @@ namespace {
value = buf;
}
-
- // Invalid commodity characters:
- // SPACE, TAB, NEWLINE, RETURN
- // 0-9 . , ; - + * / ^ ? : & | ! =
- // < > { } [ ] ( ) @
-
- int invalid_chars[256] = {
- /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
- /* 00 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0,
- /* 10 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- /* 20 */ 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1,
- /* 30 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- /* 40 */ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- /* 50 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0,
- /* 60 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- /* 70 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0,
- /* 80 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- /* 90 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- /* a0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- /* b0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- /* c0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- /* d0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- /* e0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- /* f0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- };
-
- static void parse_commodity(std::istream& in, string& symbol)
- {
- char buf[256];
- char c = peek_next_nonws(in);
- if (c == '"') {
- in.get(c);
- READ_INTO(in, buf, 255, c, c != '"');
- if (c == '"')
- in.get(c);
- else
- throw_(amount_error, "Quoted commodity symbol lacks closing quote");
- } else {
- READ_INTO(in, buf, 255, c, ! invalid_chars[(unsigned char)c]);
- }
- symbol = buf;
- }
-
- bool parse_annotations(std::istream& in, annotation_t& details)
- {
- do {
- char buf[256];
- char c = peek_next_nonws(in);
- if (c == '{') {
- if (details.price)
- throw_(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");
-
- amount_t temp;
- temp.parse(buf, AMOUNT_PARSE_NO_MIGRATE);
- temp.in_place_reduce();
-
- // Since this price will maintain its own precision, make sure
- // it is at least as large as the base commodity, since the user
- // may have only specified {$1} or something similar.
-
- if (temp.has_commodity() &&
- temp.precision() < temp.commodity().precision())
- temp = temp.round(); // no need to retain individual precision
-
- details.price = temp;
- }
- else if (c == '[') {
- if (details.date)
- throw_(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");
-
- details.date = parse_datetime(buf);
- }
- else if (c == '(') {
- if (details.tag)
- throw_(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");
-
- details.tag = buf;
- }
- else {
- break;
- }
- } while (true);
-
- DEBUG("amounts.commodities",
- "Parsed commodity annotations: "
- << " price "
- << (details.price ? details.price->to_string() : "NONE") << " "
- << " date "
- << (details.date ? *details.date : moment_t()) << " "
- << " tag "
- << (details.tag ? *details.tag : "NONE"));
-
- return details;
- }
}
void amount_t::parse(std::istream& in, flags_t flags)
@@ -1029,16 +890,16 @@ void amount_t::parse(std::istream& in, flags_t flags)
if (std::isspace(n))
comm_flags |= COMMODITY_STYLE_SEPARATED;
- parse_commodity(in, symbol);
+ commodity_t::parse_symbol(in, symbol);
if (! symbol.empty())
comm_flags |= COMMODITY_STYLE_SUFFIXED;
if (! in.eof() && ((n = in.peek()) != '\n'))
- parse_annotations(in, details);
+ details.parse(in);
}
} else {
- parse_commodity(in, symbol);
+ commodity_t::parse_symbol(in, symbol);
if (! in.eof() && ((n = in.peek()) != '\n')) {
if (std::isspace(in.peek()))
@@ -1047,7 +908,7 @@ void amount_t::parse(std::istream& in, flags_t flags)
parse_quantity(in, quant);
if (! quant.empty() && ! in.eof() && ((n = in.peek()) != '\n'))
- parse_annotations(in, details);
+ details.parse(in);
}
}
@@ -1345,8 +1206,18 @@ void amount_t::print(std::ostream& _out, bool omit_commodity,
}
+namespace {
+ char * bigints;
+ char * bigints_next;
+ uint_fast32_t bigints_index;
+ uint_fast32_t bigints_count;
+ char buf[4096];
+}
+
void amount_t::read(std::istream& in)
{
+ // Read in the commodity for this amount
+
commodity_t::ident_t ident;
read_binary_long(in, ident);
if (ident == 0xffffffff)
@@ -1358,11 +1229,44 @@ void amount_t::read(std::istream& in)
assert(commodity_);
}
- read_quantity(in);
+ // Read in the quantity
+
+ char byte;
+ in.read(&byte, sizeof(byte));
+
+ if (byte == 0) {
+ quantity = NULL;
+ }
+ else if (byte == 1) {
+ quantity = new bigint_t;
+
+ unsigned short len;
+ in.read((char *)&len, sizeof(len));
+ assert(len < 4096);
+ in.read(buf, len);
+ mpz_import(MPZ(quantity), len / sizeof(short), 1, sizeof(short),
+ 0, 0, buf);
+
+ char negative;
+ in.read(&negative, sizeof(negative));
+ if (negative)
+ mpz_neg(MPZ(quantity), MPZ(quantity));
+
+ in.read((char *)&quantity->prec, sizeof(quantity->prec));
+
+ bigint_t::flags_t tflags;
+ in.read((char *)&tflags, sizeof(tflags));
+ quantity->set_flags(tflags);
+ }
+ else {
+ assert(false);
+ }
}
void amount_t::read(char *& data)
{
+ // Read in the commodity for this amount
+
commodity_t::ident_t ident;
read_binary_long(data, ident);
if (ident == 0xffffffff)
@@ -1374,31 +1278,8 @@ void amount_t::read(char *& data)
assert(commodity_);
}
- read_quantity(data);
-}
+ // Read in the quantity
-void amount_t::write(std::ostream& out) const
-{
- if (! quantity)
- throw_(amount_error, "Cannot serialize an uninitialized amount");
-
- if (commodity_)
- write_binary_long(out, commodity_->ident);
- else
- write_binary_long<commodity_t::ident_t>(out, 0xffffffff);
-
- write_quantity(out);
-}
-
-#ifndef THREADSAFE
-static char * bigints;
-static char * bigints_next;
-static uint_fast32_t bigints_index;
-static uint_fast32_t bigints_count;
-#endif
-
-void amount_t::read_quantity(char *& data)
-{
char byte = *data++;;
if (byte == 0) {
@@ -1434,50 +1315,22 @@ void amount_t::read_quantity(char *& data)
}
}
-#ifndef THREADSAFE
-static char buf[4096];
-#endif
-
-void amount_t::read_quantity(std::istream& in)
+void amount_t::write(std::ostream& out) const
{
- char byte;
- in.read(&byte, sizeof(byte));
-
- if (byte == 0) {
- quantity = NULL;
- }
- else if (byte == 1) {
- quantity = new bigint_t;
-
- unsigned short len;
- in.read((char *)&len, sizeof(len));
- assert(len < 4096);
- in.read(buf, len);
- mpz_import(MPZ(quantity), len / sizeof(short), 1, sizeof(short),
- 0, 0, buf);
-
- char negative;
- in.read(&negative, sizeof(negative));
- if (negative)
- mpz_neg(MPZ(quantity), MPZ(quantity));
+ // Write out the commodity for this amount
+
+ if (! quantity)
+ throw_(amount_error, "Cannot serialize an uninitialized amount");
- in.read((char *)&quantity->prec, sizeof(quantity->prec));
+ if (commodity_)
+ write_binary_long(out, commodity_->ident);
+ else
+ write_binary_long<commodity_t::ident_t>(out, 0xffffffff);
- bigint_t::flags_t tflags;
- in.read((char *)&tflags, sizeof(tflags));
- quantity->set_flags(tflags);
- }
- else {
- assert(false);
- }
-}
+ // Write out the quantity
-void amount_t::write_quantity(std::ostream& out) const
-{
char byte;
- assert(quantity);
-
if (quantity->index == 0) {
quantity->index = ++bigints_index;
bigints_count++;
diff --git a/src/amount.h b/src/amount.h
index 9ac6ec0a..2f360f72 100644
--- a/src/amount.h
+++ b/src/amount.h
@@ -621,15 +621,8 @@ public:
*/
void read(std::istream& in);
void read(char *& data);
-
void write(std::ostream& out) const;
-private:
- void read_quantity(std::istream& in);
- void read_quantity(char *& data);
- void write_quantity(std::ostream& out) const;
-
-public:
/**
* Debugging methods. There are two methods defined to help with
* debugging:
diff --git a/src/commodity.cc b/src/commodity.cc
index b94aedc7..66c4a04c 100644
--- a/src/commodity.cc
+++ b/src/commodity.cc
@@ -40,6 +40,7 @@
*/
#include "amount.h"
+#include "parser.h" // for parsing utility functions
namespace ledger {
@@ -143,6 +144,48 @@ bool commodity_t::symbol_needs_quotes(const string& symbol)
return false;
}
+void commodity_t::parse_symbol(std::istream& in, string& symbol)
+{
+ // Invalid commodity characters:
+ // SPACE, TAB, NEWLINE, RETURN
+ // 0-9 . , ; - + * / ^ ? : & | ! =
+ // < > { } [ ] ( ) @
+
+ static int invalid_chars[256] = {
+ /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
+ /* 00 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0,
+ /* 10 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 20 */ 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1,
+ /* 30 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ /* 40 */ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 50 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0,
+ /* 60 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 70 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0,
+ /* 80 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 90 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* a0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* b0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* c0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* d0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* e0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* f0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ };
+
+ char buf[256];
+ char c = peek_next_nonws(in);
+ if (c == '"') {
+ in.get(c);
+ READ_INTO(in, buf, 255, c, c != '"');
+ if (c == '"')
+ in.get(c);
+ else
+ throw_(amount_error, "Quoted commodity symbol lacks closing quote");
+ } else {
+ READ_INTO(in, buf, 255, c, ! invalid_chars[(unsigned char)c]);
+ }
+ symbol = buf;
+}
+
bool commodity_t::valid() const
{
if (symbol().empty() && this != parent().null_commodity) {
@@ -164,6 +207,71 @@ bool commodity_t::valid() const
return true;
}
+void annotation_t::parse(std::istream& in)
+{
+ do {
+ char buf[256];
+ char c = peek_next_nonws(in);
+ if (c == '{') {
+ if (price)
+ throw_(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");
+
+ amount_t temp;
+ temp.parse(buf, AMOUNT_PARSE_NO_MIGRATE);
+ temp.in_place_reduce();
+
+ // Since this price will maintain its own precision, make sure
+ // it is at least as large as the base commodity, since the user
+ // may have only specified {$1} or something similar.
+
+ if (temp.has_commodity() &&
+ temp.precision() < temp.commodity().precision())
+ temp = temp.round(); // no need to retain individual precision
+
+ price = temp;
+ }
+ else if (c == '[') {
+ if (date)
+ throw_(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");
+
+ date = parse_datetime(buf);
+ }
+ else if (c == '(') {
+ if (tag)
+ throw_(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");
+
+ tag = buf;
+ }
+ else {
+ break;
+ }
+ } while (true);
+
+ DEBUG("amounts.commodities",
+ "Parsed commodity annotations: " << std::endl << *this);
+}
+
bool annotated_commodity_t::operator==(const commodity_t& comm) const
{
// If the base commodities don't match, the game's up.
@@ -180,9 +288,38 @@ bool annotated_commodity_t::operator==(const commodity_t& comm) const
return true;
}
-void
-annotated_commodity_t::write_annotations(std::ostream& out,
- const annotation_t& info)
+commodity_t&
+annotated_commodity_t::strip_annotations(const bool _keep_price,
+ const bool _keep_date,
+ const bool _keep_tag)
+{
+ DEBUG("commodity.annotated.strip",
+ "Reducing commodity " << *this << std::endl
+ << " keep price " << _keep_price << " "
+ << " keep date " << _keep_date << " "
+ << " keep tag " << _keep_tag);
+
+ commodity_t * new_comm;
+
+ if ((_keep_price && details.price) ||
+ (_keep_date && details.date) ||
+ (_keep_tag && details.tag))
+ {
+ new_comm = parent().find_or_create
+ (referent(),
+ annotation_t(_keep_price ? details.price : optional<amount_t>(),
+ _keep_date ? details.date : optional<moment_t>(),
+ _keep_tag ? details.tag : optional<string>()));
+ } else {
+ new_comm = parent().find_or_create(base_symbol());
+ }
+
+ assert(new_comm);
+ return *new_comm;
+}
+
+void annotated_commodity_t::write_annotations(std::ostream& out,
+ const annotation_t& info)
{
if (info.price)
out << " {" << *info.price << '}';
diff --git a/src/commodity.h b/src/commodity.h
index f6e888f3..6551d3b5 100644
--- a/src/commodity.h
+++ b/src/commodity.h
@@ -190,10 +190,21 @@ public:
optional<amount_t> value(const optional<moment_t>& moment =
optional<moment_t>());
+ static void parse_symbol(std::istream& in, string& symbol);
+ static string parse_symbol(std::istream& in) {
+ string temp;
+ parse_symbol(in, temp);
+ return temp;
+ }
+
void print(std::ostream& out) const {
out << symbol();
}
+ void read(std::istream& in);
+ void read(char *& data);
+ void write(std::ostream& out) const;
+
bool valid() const;
};
@@ -224,6 +235,7 @@ struct annotation_t : public equality_comparable<annotation_t>
tag == rhs.tag);
}
+ void parse(std::istream& in);
void print(std::ostream& out) const {
out << "price " << (price ? price->to_string() : "NONE") << " "
<< "date " << (date ? *date : moment_t()) << " "
@@ -273,6 +285,10 @@ public:
return *ptr;
}
+ commodity_t& strip_annotations(const bool _keep_price,
+ const bool _keep_date,
+ const bool _keep_tag);
+
void write_annotations(std::ostream& out) const {
annotated_commodity_t::write_annotations(out, details);
}