Move commodity-related parsing code from amount.cc into commodity.cc.

This commit is contained in:
John Wiegley 2007-05-09 07:43:29 +00:00
parent 42d799a1fd
commit 623e6e024c
4 changed files with 237 additions and 238 deletions

View file

@ -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,49 +1315,21 @@ 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
{
// 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;
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) {
quantity->index = ++bigints_index;

View file

@ -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:

View file

@ -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 << '}';

View file

@ -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);
}