Move commodity-related parsing code from amount.cc into commodity.cc.
This commit is contained in:
parent
42d799a1fd
commit
623e6e024c
4 changed files with 237 additions and 238 deletions
309
src/amount.cc
309
src/amount.cc
|
|
@ -799,49 +799,6 @@ void amount_t::annotate_commodity(const annotation_t& details)
|
||||||
DEBUG("amounts.commodities", " Annotated amount is " << *this);
|
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
|
bool amount_t::commodity_annotated() const
|
||||||
{
|
{
|
||||||
if (! quantity)
|
if (! quantity)
|
||||||
|
|
@ -867,6 +824,25 @@ annotation_t amount_t::annotation_details() const
|
||||||
return annotation_t();
|
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 {
|
namespace {
|
||||||
void parse_quantity(std::istream& in, string& value)
|
void parse_quantity(std::istream& in, string& value)
|
||||||
{
|
{
|
||||||
|
|
@ -883,121 +859,6 @@ namespace {
|
||||||
|
|
||||||
value = buf;
|
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)
|
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))
|
if (std::isspace(n))
|
||||||
comm_flags |= COMMODITY_STYLE_SEPARATED;
|
comm_flags |= COMMODITY_STYLE_SEPARATED;
|
||||||
|
|
||||||
parse_commodity(in, symbol);
|
commodity_t::parse_symbol(in, 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, details);
|
details.parse(in);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
parse_commodity(in, symbol);
|
commodity_t::parse_symbol(in, 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()))
|
||||||
|
|
@ -1047,7 +908,7 @@ void amount_t::parse(std::istream& in, flags_t flags)
|
||||||
parse_quantity(in, quant);
|
parse_quantity(in, quant);
|
||||||
|
|
||||||
if (! quant.empty() && ! in.eof() && ((n = in.peek()) != '\n'))
|
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)
|
void amount_t::read(std::istream& in)
|
||||||
{
|
{
|
||||||
|
// Read in the commodity for this amount
|
||||||
|
|
||||||
commodity_t::ident_t ident;
|
commodity_t::ident_t ident;
|
||||||
read_binary_long(in, ident);
|
read_binary_long(in, ident);
|
||||||
if (ident == 0xffffffff)
|
if (ident == 0xffffffff)
|
||||||
|
|
@ -1358,11 +1229,44 @@ void amount_t::read(std::istream& in)
|
||||||
assert(commodity_);
|
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)
|
void amount_t::read(char *& data)
|
||||||
{
|
{
|
||||||
|
// Read in the commodity for this amount
|
||||||
|
|
||||||
commodity_t::ident_t ident;
|
commodity_t::ident_t ident;
|
||||||
read_binary_long(data, ident);
|
read_binary_long(data, ident);
|
||||||
if (ident == 0xffffffff)
|
if (ident == 0xffffffff)
|
||||||
|
|
@ -1374,31 +1278,8 @@ void amount_t::read(char *& data)
|
||||||
assert(commodity_);
|
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++;;
|
char byte = *data++;;
|
||||||
|
|
||||||
if (byte == 0) {
|
if (byte == 0) {
|
||||||
|
|
@ -1434,49 +1315,21 @@ void amount_t::read_quantity(char *& data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef THREADSAFE
|
void amount_t::write(std::ostream& out) const
|
||||||
static char buf[4096];
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void amount_t::read_quantity(std::istream& in)
|
|
||||||
{
|
{
|
||||||
|
// Write out the commodity for this amount
|
||||||
|
|
||||||
|
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 out the quantity
|
||||||
|
|
||||||
char byte;
|
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::write_quantity(std::ostream& out) const
|
|
||||||
{
|
|
||||||
char byte;
|
|
||||||
|
|
||||||
assert(quantity);
|
|
||||||
|
|
||||||
if (quantity->index == 0) {
|
if (quantity->index == 0) {
|
||||||
quantity->index = ++bigints_index;
|
quantity->index = ++bigints_index;
|
||||||
|
|
|
||||||
|
|
@ -621,15 +621,8 @@ public:
|
||||||
*/
|
*/
|
||||||
void read(std::istream& in);
|
void read(std::istream& in);
|
||||||
void read(char *& data);
|
void read(char *& data);
|
||||||
|
|
||||||
void write(std::ostream& out) const;
|
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 methods. There are two methods defined to help with
|
||||||
* debugging:
|
* debugging:
|
||||||
|
|
|
||||||
141
src/commodity.cc
141
src/commodity.cc
|
|
@ -40,6 +40,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "amount.h"
|
#include "amount.h"
|
||||||
|
#include "parser.h" // for parsing utility functions
|
||||||
|
|
||||||
namespace ledger {
|
namespace ledger {
|
||||||
|
|
||||||
|
|
@ -143,6 +144,48 @@ bool commodity_t::symbol_needs_quotes(const string& symbol)
|
||||||
return false;
|
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
|
bool commodity_t::valid() const
|
||||||
{
|
{
|
||||||
if (symbol().empty() && this != parent().null_commodity) {
|
if (symbol().empty() && this != parent().null_commodity) {
|
||||||
|
|
@ -164,6 +207,71 @@ bool commodity_t::valid() const
|
||||||
return true;
|
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
|
bool annotated_commodity_t::operator==(const commodity_t& comm) const
|
||||||
{
|
{
|
||||||
// If the base commodities don't match, the game's up.
|
// If the base commodities don't match, the game's up.
|
||||||
|
|
@ -180,8 +288,37 @@ bool annotated_commodity_t::operator==(const commodity_t& comm) const
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
commodity_t&
|
||||||
annotated_commodity_t::write_annotations(std::ostream& out,
|
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)
|
const annotation_t& info)
|
||||||
{
|
{
|
||||||
if (info.price)
|
if (info.price)
|
||||||
|
|
|
||||||
|
|
@ -190,10 +190,21 @@ public:
|
||||||
optional<amount_t> value(const optional<moment_t>& moment =
|
optional<amount_t> value(const optional<moment_t>& moment =
|
||||||
optional<moment_t>());
|
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 {
|
void print(std::ostream& out) const {
|
||||||
out << symbol();
|
out << symbol();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void read(std::istream& in);
|
||||||
|
void read(char *& data);
|
||||||
|
void write(std::ostream& out) const;
|
||||||
|
|
||||||
bool valid() const;
|
bool valid() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -224,6 +235,7 @@ struct annotation_t : public equality_comparable<annotation_t>
|
||||||
tag == rhs.tag);
|
tag == rhs.tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void parse(std::istream& in);
|
||||||
void print(std::ostream& out) const {
|
void print(std::ostream& out) const {
|
||||||
out << "price " << (price ? price->to_string() : "NONE") << " "
|
out << "price " << (price ? price->to_string() : "NONE") << " "
|
||||||
<< "date " << (date ? *date : moment_t()) << " "
|
<< "date " << (date ? *date : moment_t()) << " "
|
||||||
|
|
@ -273,6 +285,10 @@ public:
|
||||||
return *ptr;
|
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 {
|
void write_annotations(std::ostream& out) const {
|
||||||
annotated_commodity_t::write_annotations(out, details);
|
annotated_commodity_t::write_annotations(out, details);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue