diff options
author | John Wiegley <johnw@newartisans.com> | 2007-05-09 07:43:29 +0000 |
---|---|---|
committer | John Wiegley <johnw@newartisans.com> | 2008-04-13 03:38:42 -0400 |
commit | 623e6e024cf43fc855c889314b8da8802c2f0449 (patch) | |
tree | ed00d4a4c36146ed9a2ff9db503777a0edd4c842 /src | |
parent | 42d799a1fdde6278fe42be58786937e49fcf1c3f (diff) | |
download | fork-ledger-623e6e024cf43fc855c889314b8da8802c2f0449.tar.gz fork-ledger-623e6e024cf43fc855c889314b8da8802c2f0449.tar.bz2 fork-ledger-623e6e024cf43fc855c889314b8da8802c2f0449.zip |
Move commodity-related parsing code from amount.cc into commodity.cc.
Diffstat (limited to 'src')
-rw-r--r-- | src/amount.cc | 303 | ||||
-rw-r--r-- | src/amount.h | 7 | ||||
-rw-r--r-- | src/commodity.cc | 143 | ||||
-rw-r--r-- | src/commodity.h | 16 |
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); } |