From 4bddaff78ec1ee99521eb8774cafe3a1e7c6d36c Mon Sep 17 00:00:00 2001 From: Tim Landscheidt Date: Tue, 22 Jan 2019 14:41:41 +0000 Subject: Move garbage-input.dat to test case using it --- test/garbage-input.dat | 793 --------------------------------------------- test/regress/25A099C9.dat | 793 +++++++++++++++++++++++++++++++++++++++++++++ test/regress/25A099C9.test | 60 ++-- 3 files changed, 823 insertions(+), 823 deletions(-) delete mode 100644 test/garbage-input.dat create mode 100644 test/regress/25A099C9.dat (limited to 'test') diff --git a/test/garbage-input.dat b/test/garbage-input.dat deleted file mode 100644 index 1b7d2101..00000000 --- a/test/garbage-input.dat +++ /dev/null @@ -1,793 +0,0 @@ -/* - * Copyright (c) 2003-2012, John Wiegley. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of New Artisans LLC nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @defgroup math Mathematical objects - */ - -/** - * @file amount.h - * @author John Wiegley - * - * @ingroup math - * - * @brief Basic type for handling commoditized math: amount_t - * - * An amount is the most basic numerical type in Ledger, and relies on - * commodity.h to represent commoditized amounts, which allows Ledger to - * handle mathematical expressions involving disparate commodities. - * - * Amounts can be of virtually infinite size and precision. When - * division or multiplication is performed, the precision is - * automatically expanded to include as many extra digits as necessary - * to avoid losing information. - */ -#ifndef _AMOUNT_H -#define _AMOUNT_H - -#include "utils.h" -#include "times.h" -#include "flags.h" - -namespace ledger { - -class commodity_t; -struct annotation_t; -struct keep_details_t; - -DECLARE_EXCEPTION(amount_error, std::runtime_error); - -enum parse_flags_enum_t { - PARSE_DEFAULT = 0x00, - PARSE_PARTIAL = 0x01, - PARSE_SINGLE = 0x02, - PARSE_NO_MIGRATE = 0x04, - PARSE_NO_REDUCE = 0x08, - PARSE_NO_ASSIGN = 0x10, - PARSE_NO_ANNOT = 0x20, - PARSE_OP_CONTEXT = 0x40, - PARSE_SOFT_FAIL = 0x80 -}; - -typedef basic_flags_t parse_flags_t; - -/** - * @brief Encapsulate infinite-precision commoditized amounts - * - * Used to represent commoditized infinite-precision numbers, and - * uncommoditized, plain numbers. In the commoditized case, commodities - * keep track of how they are used, and are always displayed back to the - * user after the same fashion. For uncommoditized numbers, no display - * truncation is ever done. In both cases, internal precision is always - * kept to an excessive degree. - */ -class amount_t - : public ordered_field_operators > > > -{ -public: - /** Ready the amount subsystem for use. - @note Normally called by session_t::initialize(). */ - static void initialize(); - /** Shutdown the amount subsystem and free all resources. - @note Normally called by session_t::shutdown(). */ - static void shutdown(); - - static bool is_initialized; - - /** The amount's decimal precision. */ - typedef uint_least16_t precision_t; - - /** Number of places of precision by which values are extended to - avoid losing precision during division and multiplication. */ - static const std::size_t extend_by_digits = 6U; - - /** If amounts should be streamed using to_fullstring() rather than - to_string(), so that complete precision is always displayed no matter - what the precision of an individual commodity may be. */ - static bool stream_fullstrings; - -protected: - void _copy(const amount_t& amt); - void _dup(); - void _clear(); - void _release(); - - struct bigint_t; - - bigint_t * quantity; - commodity_t * commodity_; - -public: - /** @name Constructors - @{ */ - - /** Creates a value for which is_null() is true, and which has no - value or commodity. If used in a value expression it evaluates to - zero, and its commodity equals \c commodity_t::null_commodity. */ - amount_t() : quantity(NULL), commodity_(NULL) { - TRACE_CTOR(amount_t, ""); - } - - /** Convert a double to an amount. As much precision as possible is - decoded from the binary floating point number. */ - amount_t(const double val); - - /** Convert an unsigned long to an amount. It's precision is zero. */ - amount_t(const unsigned long val); - - /** Convert a long to an amount. It's precision is zero, and the sign - is preserved. */ - amount_t(const long val); - - /** Parse a string as an (optionally commoditized) amount. If no - commodity is present, the resulting commodity is \c - commodity_t::null_commodity. The number may be of infinite - precision. */ - explicit amount_t(const string& val) : quantity(NULL) { - parse(val); - TRACE_CTOR(amount_t, "const string&"); - } - /** Parse a pointer to a C string as an (optionally commoditized) - amount. If no commodity is present, the resulting commodity is \c - commodity_t::null_commodity. The number may be of infinite - precision. */ - explicit amount_t(const char * val) : quantity(NULL) { - assert(val); - parse(val); - TRACE_CTOR(amount_t, "const char *"); - } - - /*@}*/ - - /** Create an amount whose display precision is never truncated, even - if the amount uses a commodity (which normally causes "round on - streaming" to occur). This function is mostly used by debugging - code and unit tests. This is the proper way to specify \c - $100.005, where display of the extra digit precision is required. - If a regular constructor were used, the amount would stream as \c - $100.01, even though its internal value equals \c $100.005. */ - static amount_t exact(const string& value); - - /** Release the reference count held for the underlying \c - amount_t::bigint_t object. */ - ~amount_t() { - TRACE_DTOR(amount_t); - if (quantity) - _release(); - } - - /** @name Assignment and copy - @{*/ - - /** Copy an amount object. Copies are very efficient, using a - copy-on-write model. Until the copy is changed, it refers to the - same memory used by the original via reference counting. The \c - amount_t::bigint_t class in amount.cc maintains the reference. */ - amount_t(const amount_t& amt) : quantity(NULL) { - if (amt.quantity) - _copy(amt); - else - commodity_ = NULL; - TRACE_CTOR(amount_t, "copy"); - } - /** Copy an amount object, applying the given commodity annotation - details afterward. This is equivalent to doing a normal copy - (@see amount_t(const amount_t&)) and then calling - amount_t::annotate(). */ - amount_t(const amount_t& amt, const annotation_t& details) : quantity(NULL) { - assert(amt.quantity); - _copy(amt); - annotate(details); - TRACE_CTOR(amount_t, "const amount_t&, const annotation_t&"); - } - /** Assign an amount object. This is like copying if the amount was - null beforehand, otherwise the previous value's reference is must - be freed. */ - amount_t& operator=(const amount_t& amt); - - amount_t& operator=(const double val) { - return *this = amount_t(val); - } - amount_t& operator=(const unsigned long val) { - return *this = amount_t(val); - } - amount_t& operator=(const long val) { - return *this = amount_t(val); - } - - /* Assign a string to an amount. This causes the contents of the - string to be parsed, look for a commoditized or uncommoditized - amount specifier. */ - amount_t& operator=(const string& str) { - return *this = amount_t(str); - } - amount_t& operator=(const char * str) { - assert(str); - return *this = amount_t(str); - } - - /*@}*/ - - /** @name Comparison - @{ */ - - /** Compare two amounts, returning a number less than zero if \p amt - is greater, exactly zero if they are equal, and greater than zero - if \p amt is less. This method is used to implement all of the - other comparison methods.*/ - int compare(const amount_t& amt) const; - - /** Test two amounts for equality. First the commodity pointers are - quickly tested, then the multi-precision values themselves must be - compared. */ - bool operator==(const amount_t& amt) const; - - template - bool operator==(const T& val) const { - return compare(val) == 0; - } - template - bool operator<(const T& amt) const { - return compare(amt) < 0; - } - template - bool operator>(const T& amt) const { - return compare(amt) > 0; - } - - /*@}*/ - - /** @name Binary arithmetic - */ - /*@{*/ - - amount_t& operator+=(const amount_t& amt); - amount_t& operator-=(const amount_t& amt); - amount_t& operator*=(const amount_t& amt) { - return multiply(amt); - } - amount_t& multiply(const amount_t& amt, bool ignore_commodity = false); - - /** Divide two amounts while extending the precision to preserve the - accuracy of the result. For example, if \c 10 is divided by \c 3, - the result ends up having a precision of \link - amount_t::extend_by_digits \endlink place to avoid losing internal - resolution. */ - amount_t& operator/=(const amount_t& amt); - - /*@}*/ - - /** @name Unary arithmetic - @{ */ - - /** Return an amount's internal precision. To find the precision it - should be displayed at -- assuming it was not created using - amount_t::exact() -- use the following expression instead: - @code - amount.commodity().precision() - @endcode */ - precision_t precision() const; - bool keep_precision() const; - void set_keep_precision(const bool keep = true) const; - precision_t display_precision() const; - - /** Returns the negated value of an amount. - @see operator-() - */ - amount_t negated() const { - amount_t temp(*this); - temp.in_place_negate(); - return temp; - } - void in_place_negate(); - - amount_t operator-() const { - return negated(); - } - - /** Returns the absolute value of an amount. Equivalent to: - @code - (x < * 0) ? - x : x - @endcode - */ - amount_t abs() const { - if (sign() < 0) - return negated(); - return *this; - } - - amount_t inverted() const { - amount_t temp(*this); - temp.in_place_invert(); - return temp; - } - void in_place_invert(); - - /** Yields an amount whose display precision when output is truncated - to the display precision of its commodity. This is normally the - default state of an amount, but if one has become unrounded, this - sets the "keep precision" state back to false. - @see set_keep_precision */ - amount_t rounded() const { - amount_t temp(*this); - temp.in_place_round(); - return temp; - } - void in_place_round(); - - /** Yields an amount which has lost all of its extra precision, beyond what - the display precision of the commodity would have printed. */ - amount_t truncated() const { - amount_t temp(*this); - temp.in_place_truncate(); - return temp; - } - void in_place_truncate(); - - /** Yields an amount which has lost all of its extra precision, beyond what - the display precision of the commodity would have printed. */ - amount_t floored() const { - amount_t temp(*this); - temp.in_place_floor(); - return temp; - } - void in_place_floor(); - - /** Yields an amount which has lost all of its extra precision, beyond what - the display precision of the commodity would have printed. */ - amount_t ceilinged() const { - amount_t temp(*this); - temp.in_place_ceiling(); - return temp; - } - void in_place_ceiling(); - - /** Yields an amount whose display precision is never truncated, even - though its commodity normally displays only rounded values. */ - amount_t unrounded() const { - amount_t temp(*this); - temp.in_place_unround(); - return temp; - } - void in_place_unround(); - - /** reduces a value to its most basic commodity form, for amounts that - utilize "scaling commodities". For example, an amount of \c 1h - after reduction will be \c 3600s. - */ - amount_t reduced() const { - amount_t temp(*this); - temp.in_place_reduce(); - return temp; - } - void in_place_reduce(); - - /** unreduce(), if used with a "scaling commodity", yields the most - compact form greater than one. That is, \c 3599s will unreduce to - \c 59.98m, while \c 3601 unreduces to \c 1h. - */ - amount_t unreduced() const { - amount_t temp(*this); - temp.in_place_unreduce(); - return temp; - } - void in_place_unreduce(); - - /** Returns the historical value for an amount -- the default moment - returns the most recently known price -- based on the price history - for the given commodity (or determined automatically, if none is - provided). For example, if the amount were 10 AAPL, and - on Apr 10, 2000 each share of \c AAPL was worth \c $10, then - calling value() for that moment in time would yield the amount \c - $100.00. - */ - optional - value(const datetime_t& moment = datetime_t(), - const commodity_t * in_terms_of = NULL) const; - - optional price() const; - - /*@}*/ - - /** @name Truth tests - */ - /*@{*/ - - /** Truth tests. An amount may be truth test in several ways: - - sign() returns an integer less than, greater than, or equal to - zero depending on whether the amount is negative, zero, or - greater than zero. Note that this function tests the actual - value of the amount -- using its internal precision -- and not - the display value. To test its display value, use: - `round().sign()'. - - is_nonzero(), or operator bool, returns true if an amount's - display value is not zero. - - is_zero() returns true if an amount's display value is zero. - Thus, $0.0001 is considered zero if the current display precision - for dollars is two decimal places. - - is_realzero() returns true if an amount's actual value is zero. - Thus, $0.0001 is never considered realzero. - - is_null() returns true if an amount has no value and no - commodity. This only occurs if an uninitialized amount has never - been assigned a value. - */ - int sign() const; - - operator bool() const { - return is_nonzero(); - } - bool is_nonzero() const { - return ! is_zero(); - } - - bool is_zero() const; - bool is_realzero() const { - return sign() == 0; - } - - bool is_null() const { - if (! quantity) { - assert(! commodity_); - return true; - } - return false; - } - - /*@}*/ - - /** @name Conversion - */ - /*@{*/ - - /** Conversion methods. An amount may be converted to the same types - it can be constructed from -- with the exception of unsigned - long. Implicit conversions are not allowed in C++ (though they - are in Python), rather the following conversion methods must be - called explicitly: - - to_double([bool]) returns an amount as a double. If the optional - boolean argument is true (the default), an exception is thrown if - the conversion would lose information. - - to_long([bool]) returns an amount as a long integer. If the - optional boolean argument is true (the default), an exception is - thrown if the conversion would lose information. - - fits_in_long() returns true if to_long() would not lose - precision. - - to_string() returns an amount'ss "display value" as a string -- - after rounding the value according to the commodity's default - precision. It is equivalent to: `round().to_fullstring()'. - - to_fullstring() returns an amount's "internal value" as a string, - without any rounding. - - quantity_string() returns an amount's "display value", but - without any commodity. Note that this is different from - `number().to_string()', because in that case the commodity has - been stripped and the full, internal precision of the amount - would be displayed. - */ - double to_double() const; - long to_long() const; - bool fits_in_long() const; - - operator string() const { - return to_string(); - } - string to_string() const; - string to_fullstring() const; - string quantity_string() const; - - /*@}*/ - - /** @name Commodity methods - */ - /*@{*/ - - /** The following methods relate to an - amount's commodity: - - commodity() returns an amount's commodity. If the amount has no - commodity, the value returned is the `null_commodity'. - - has_commodity() returns true if the amount has a commodity. - - set_commodity(commodity_t) sets an amount's commodity to the - given value. Note that this merely sets the current amount to - that commodity, it does not "observe" the amount for possible - changes in the maximum display precision of the commodity, the - way that `parse' does. - - clear_commodity() sets an amount's commodity to null, such that - has_commodity() afterwards returns false. - - number() returns a commodity-less version of an amount. This is - useful for accessing just the numeric portion of an amount. - */ - commodity_t * commodity_ptr() const; - commodity_t& commodity() const { - return *commodity_ptr(); - } - - bool has_commodity() const; - void set_commodity(commodity_t& comm) { - if (! quantity) - *this = 0L; - commodity_ = &comm; - } - amount_t with_commodity(const commodity_t& comm) const { - if (commodity_ == &comm) { - return *this; - } else { - amount_t tmp(*this); - tmp.set_commodity(const_cast(comm)); - return tmp; - } - } - void clear_commodity() { - commodity_ = NULL; - } - - amount_t number() const { - if (! has_commodity()) - return *this; - - amount_t temp(*this); - temp.clear_commodity(); - return temp; - } - - /*@}*/ - - /** @name Commodity annotations - */ - /*@{*/ - - /** An amount's commodity may be annotated with special details, such as the - price it was purchased for, when it was acquired, or an arbitrary note, - identifying perhaps the lot number of an item. - - annotate_commodity(amount_t price, [datetime_t date, string tag]) - sets the annotations for the current amount's commodity. Only - the price argument is required, although it can be passed as - `none' if no price is desired. - - commodity_annotated() returns true if an amount's commodity has - any annotation details associated with it. - - annotation_details() returns all of the details of an annotated - commodity's annotations. The structure returns will evaluate as - boolean false if there are no details. - - strip_annotations() returns an amount whose commodity's annotations have - been stripped. - */ - void annotate(const annotation_t& details); - bool has_annotation() const; - - annotation_t& annotation(); - const annotation_t& annotation() const { - return const_cast(*this).annotation(); - } - - /** If the lot price is considered whenever working with commoditized - values. - - Let's say a user adds two values of the following form: - @code - 10 AAPL + 10 AAPL {$20} - @endcode - - This expression adds ten shares of Apple stock with another ten - shares that were purchased for \c $20 a share. If \c keep_price - is false, the result of this expression is an amount equal to - 20 AAPL. If \c keep_price is \c true the expression - yields an exception for adding amounts with different commodities. - In that case, a \link balance_t \endlink object must be used to - store the combined sum. */ - amount_t strip_annotations(const keep_details_t& what_to_keep) const; - - /*@}*/ - - /** @name Parsing - */ - /*@{*/ - - /** The `flags' argument of both parsing may be one or more of the - following: - - PARSE_NO_MIGRATE means to not pay attention to the way an - amount is used. Ordinarily, if an amount were $100.001, for - example, it would cause the default display precision for $ to be - "widened" to three decimal places. If PARSE_NO_MIGRATE is - used, the commodity's default display precision is not changed. - - PARSE_NO_REDUCE means not to call in_place_reduce() on the - resulting amount after it is parsed. - - These parsing methods observe the amounts they parse (unless - PARSE_NO_MIGRATE is true), and set the display details of - the corresponding commodity accordingly. This way, amounts do - not require commodities to be pre-defined in any way, but merely - displays them back to the user in the same fashion as it saw them - used. - - There is also a static convenience method called - `parse_conversion' which can be used to define a relationship - between scaling commodity values. For example, Ledger uses it to - define the relationships among various time values: - - @code - amount_t::parse_conversion("1.0m", "60s"); // a minute is 60 seconds - amount_t::parse_conversion("1.0h", "60m"); // an hour is 60 minutes - @endcode - - The method parse() is used to parse an amount from an input stream - or a string. A global operator>>() is also defined which simply - calls parse on the input stream. The parse() method has two forms: - - parse(istream, flags_t) parses an amount from the given input - stream. - - parse(string, flags_t) parses an amount from the given string. - - parse(string, flags_t) also parses an amount from a string. - */ - bool parse(std::istream& in, - const parse_flags_t& flags = PARSE_DEFAULT); - bool parse(const string& str, - const parse_flags_t& flags = PARSE_DEFAULT) { - std::istringstream stream(str); - bool result = parse(stream, flags); - return result; - } - - static void parse_conversion(const string& larger_str, - const string& smaller_str); - - /*@}*/ - - /** @name Printing - */ - /*@{*/ - - /** An amount may be output to a stream using the `print' method. There is - also a global operator<< defined which simply calls print for an amount - on the given stream. There is one form of the print method, which takes - one required argument and two arguments with default values: - - print(ostream, bool omit_commodity = false, bool full_precision = false) - prints an amounts to the given output stream, using its commodity's - default display characteristics. If `omit_commodity' is true, the - commodity will not be displayed, only the amount (although the - commodity's display precision is still used). If `full_precision' is - true, the full internal precision of the amount is displayed, regardless - of its commodity's display precision. - */ -#define AMOUNT_PRINT_NO_FLAGS 0x00 -#define AMOUNT_PRINT_RIGHT_JUSTIFY 0x01 -#define AMOUNT_PRINT_COLORIZE 0x02 -#define AMOUNT_PRINT_NO_COMPUTED_ANNOTATIONS 0x04 -#define AMOUNT_PRINT_ELIDE_COMMODITY_QUOTES 0x08 - - void print(std::ostream& out, - const uint_least8_t flags = AMOUNT_PRINT_NO_FLAGS) const; - - /*@}*/ - - /** @name Debugging - */ - /*@{*/ - - /** There are two methods defined to help with debugging: - - dump(ostream) dumps an amount to an output stream. There is - little different from print(), it simply surrounds the display - value with a marker, for example "AMOUNT($1.00)". This code is - used by other dumping code elsewhere in Ledger. - - valid() returns true if an amount is valid. This ensures that if - an amount has a commodity, it has a valid value pointer, for - example, even if that pointer simply points to a zero value. - */ - void dump(std::ostream& out) const { - out << "AMOUNT("; - print(out); - out << ")"; - } - - bool valid() const; - -#if HAVE_BOOST_SERIALIZATION -private: - /** Serialization. */ - - friend class boost::serialization::access; - - template - void serialize(Archive& ar, const unsigned int /* version */); -#endif // HAVE_BOOST_SERIALIZATION - - /*@}*/ -}; - -inline amount_t amount_t::exact(const string& value) { - amount_t temp; - temp.parse(value, PARSE_NO_MIGRATE); - return temp; -} - -inline string amount_t::to_string() const { - std::ostringstream bufstream; - print(bufstream); - return bufstream.str(); -} - -inline string amount_t::to_fullstring() const { - std::ostringstream bufstream; - unrounded().print(bufstream); - return bufstream.str(); -} - -inline string amount_t::quantity_string() const { - std::ostringstream bufstream; - number().print(bufstream); - return bufstream.str(); -} - -inline std::ostream& operator<<(std::ostream& out, const amount_t& amt) { - if (amount_t::stream_fullstrings) - amt.unrounded().print(out); - else - amt.print(out); - return out; -} -inline std::istream& operator>>(std::istream& in, amount_t& amt) { - amt.parse(in); - return in; -} - -void put_amount(property_tree::ptree& pt, const amount_t& amt, - bool wrap = true, bool commodity_details = false); - -} // namespace ledger - -#endif // _AMOUNT_H diff --git a/test/regress/25A099C9.dat b/test/regress/25A099C9.dat new file mode 100644 index 00000000..1b7d2101 --- /dev/null +++ b/test/regress/25A099C9.dat @@ -0,0 +1,793 @@ +/* + * Copyright (c) 2003-2012, John Wiegley. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of New Artisans LLC nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @defgroup math Mathematical objects + */ + +/** + * @file amount.h + * @author John Wiegley + * + * @ingroup math + * + * @brief Basic type for handling commoditized math: amount_t + * + * An amount is the most basic numerical type in Ledger, and relies on + * commodity.h to represent commoditized amounts, which allows Ledger to + * handle mathematical expressions involving disparate commodities. + * + * Amounts can be of virtually infinite size and precision. When + * division or multiplication is performed, the precision is + * automatically expanded to include as many extra digits as necessary + * to avoid losing information. + */ +#ifndef _AMOUNT_H +#define _AMOUNT_H + +#include "utils.h" +#include "times.h" +#include "flags.h" + +namespace ledger { + +class commodity_t; +struct annotation_t; +struct keep_details_t; + +DECLARE_EXCEPTION(amount_error, std::runtime_error); + +enum parse_flags_enum_t { + PARSE_DEFAULT = 0x00, + PARSE_PARTIAL = 0x01, + PARSE_SINGLE = 0x02, + PARSE_NO_MIGRATE = 0x04, + PARSE_NO_REDUCE = 0x08, + PARSE_NO_ASSIGN = 0x10, + PARSE_NO_ANNOT = 0x20, + PARSE_OP_CONTEXT = 0x40, + PARSE_SOFT_FAIL = 0x80 +}; + +typedef basic_flags_t parse_flags_t; + +/** + * @brief Encapsulate infinite-precision commoditized amounts + * + * Used to represent commoditized infinite-precision numbers, and + * uncommoditized, plain numbers. In the commoditized case, commodities + * keep track of how they are used, and are always displayed back to the + * user after the same fashion. For uncommoditized numbers, no display + * truncation is ever done. In both cases, internal precision is always + * kept to an excessive degree. + */ +class amount_t + : public ordered_field_operators > > > +{ +public: + /** Ready the amount subsystem for use. + @note Normally called by session_t::initialize(). */ + static void initialize(); + /** Shutdown the amount subsystem and free all resources. + @note Normally called by session_t::shutdown(). */ + static void shutdown(); + + static bool is_initialized; + + /** The amount's decimal precision. */ + typedef uint_least16_t precision_t; + + /** Number of places of precision by which values are extended to + avoid losing precision during division and multiplication. */ + static const std::size_t extend_by_digits = 6U; + + /** If amounts should be streamed using to_fullstring() rather than + to_string(), so that complete precision is always displayed no matter + what the precision of an individual commodity may be. */ + static bool stream_fullstrings; + +protected: + void _copy(const amount_t& amt); + void _dup(); + void _clear(); + void _release(); + + struct bigint_t; + + bigint_t * quantity; + commodity_t * commodity_; + +public: + /** @name Constructors + @{ */ + + /** Creates a value for which is_null() is true, and which has no + value or commodity. If used in a value expression it evaluates to + zero, and its commodity equals \c commodity_t::null_commodity. */ + amount_t() : quantity(NULL), commodity_(NULL) { + TRACE_CTOR(amount_t, ""); + } + + /** Convert a double to an amount. As much precision as possible is + decoded from the binary floating point number. */ + amount_t(const double val); + + /** Convert an unsigned long to an amount. It's precision is zero. */ + amount_t(const unsigned long val); + + /** Convert a long to an amount. It's precision is zero, and the sign + is preserved. */ + amount_t(const long val); + + /** Parse a string as an (optionally commoditized) amount. If no + commodity is present, the resulting commodity is \c + commodity_t::null_commodity. The number may be of infinite + precision. */ + explicit amount_t(const string& val) : quantity(NULL) { + parse(val); + TRACE_CTOR(amount_t, "const string&"); + } + /** Parse a pointer to a C string as an (optionally commoditized) + amount. If no commodity is present, the resulting commodity is \c + commodity_t::null_commodity. The number may be of infinite + precision. */ + explicit amount_t(const char * val) : quantity(NULL) { + assert(val); + parse(val); + TRACE_CTOR(amount_t, "const char *"); + } + + /*@}*/ + + /** Create an amount whose display precision is never truncated, even + if the amount uses a commodity (which normally causes "round on + streaming" to occur). This function is mostly used by debugging + code and unit tests. This is the proper way to specify \c + $100.005, where display of the extra digit precision is required. + If a regular constructor were used, the amount would stream as \c + $100.01, even though its internal value equals \c $100.005. */ + static amount_t exact(const string& value); + + /** Release the reference count held for the underlying \c + amount_t::bigint_t object. */ + ~amount_t() { + TRACE_DTOR(amount_t); + if (quantity) + _release(); + } + + /** @name Assignment and copy + @{*/ + + /** Copy an amount object. Copies are very efficient, using a + copy-on-write model. Until the copy is changed, it refers to the + same memory used by the original via reference counting. The \c + amount_t::bigint_t class in amount.cc maintains the reference. */ + amount_t(const amount_t& amt) : quantity(NULL) { + if (amt.quantity) + _copy(amt); + else + commodity_ = NULL; + TRACE_CTOR(amount_t, "copy"); + } + /** Copy an amount object, applying the given commodity annotation + details afterward. This is equivalent to doing a normal copy + (@see amount_t(const amount_t&)) and then calling + amount_t::annotate(). */ + amount_t(const amount_t& amt, const annotation_t& details) : quantity(NULL) { + assert(amt.quantity); + _copy(amt); + annotate(details); + TRACE_CTOR(amount_t, "const amount_t&, const annotation_t&"); + } + /** Assign an amount object. This is like copying if the amount was + null beforehand, otherwise the previous value's reference is must + be freed. */ + amount_t& operator=(const amount_t& amt); + + amount_t& operator=(const double val) { + return *this = amount_t(val); + } + amount_t& operator=(const unsigned long val) { + return *this = amount_t(val); + } + amount_t& operator=(const long val) { + return *this = amount_t(val); + } + + /* Assign a string to an amount. This causes the contents of the + string to be parsed, look for a commoditized or uncommoditized + amount specifier. */ + amount_t& operator=(const string& str) { + return *this = amount_t(str); + } + amount_t& operator=(const char * str) { + assert(str); + return *this = amount_t(str); + } + + /*@}*/ + + /** @name Comparison + @{ */ + + /** Compare two amounts, returning a number less than zero if \p amt + is greater, exactly zero if they are equal, and greater than zero + if \p amt is less. This method is used to implement all of the + other comparison methods.*/ + int compare(const amount_t& amt) const; + + /** Test two amounts for equality. First the commodity pointers are + quickly tested, then the multi-precision values themselves must be + compared. */ + bool operator==(const amount_t& amt) const; + + template + bool operator==(const T& val) const { + return compare(val) == 0; + } + template + bool operator<(const T& amt) const { + return compare(amt) < 0; + } + template + bool operator>(const T& amt) const { + return compare(amt) > 0; + } + + /*@}*/ + + /** @name Binary arithmetic + */ + /*@{*/ + + amount_t& operator+=(const amount_t& amt); + amount_t& operator-=(const amount_t& amt); + amount_t& operator*=(const amount_t& amt) { + return multiply(amt); + } + amount_t& multiply(const amount_t& amt, bool ignore_commodity = false); + + /** Divide two amounts while extending the precision to preserve the + accuracy of the result. For example, if \c 10 is divided by \c 3, + the result ends up having a precision of \link + amount_t::extend_by_digits \endlink place to avoid losing internal + resolution. */ + amount_t& operator/=(const amount_t& amt); + + /*@}*/ + + /** @name Unary arithmetic + @{ */ + + /** Return an amount's internal precision. To find the precision it + should be displayed at -- assuming it was not created using + amount_t::exact() -- use the following expression instead: + @code + amount.commodity().precision() + @endcode */ + precision_t precision() const; + bool keep_precision() const; + void set_keep_precision(const bool keep = true) const; + precision_t display_precision() const; + + /** Returns the negated value of an amount. + @see operator-() + */ + amount_t negated() const { + amount_t temp(*this); + temp.in_place_negate(); + return temp; + } + void in_place_negate(); + + amount_t operator-() const { + return negated(); + } + + /** Returns the absolute value of an amount. Equivalent to: + @code + (x < * 0) ? - x : x + @endcode + */ + amount_t abs() const { + if (sign() < 0) + return negated(); + return *this; + } + + amount_t inverted() const { + amount_t temp(*this); + temp.in_place_invert(); + return temp; + } + void in_place_invert(); + + /** Yields an amount whose display precision when output is truncated + to the display precision of its commodity. This is normally the + default state of an amount, but if one has become unrounded, this + sets the "keep precision" state back to false. + @see set_keep_precision */ + amount_t rounded() const { + amount_t temp(*this); + temp.in_place_round(); + return temp; + } + void in_place_round(); + + /** Yields an amount which has lost all of its extra precision, beyond what + the display precision of the commodity would have printed. */ + amount_t truncated() const { + amount_t temp(*this); + temp.in_place_truncate(); + return temp; + } + void in_place_truncate(); + + /** Yields an amount which has lost all of its extra precision, beyond what + the display precision of the commodity would have printed. */ + amount_t floored() const { + amount_t temp(*this); + temp.in_place_floor(); + return temp; + } + void in_place_floor(); + + /** Yields an amount which has lost all of its extra precision, beyond what + the display precision of the commodity would have printed. */ + amount_t ceilinged() const { + amount_t temp(*this); + temp.in_place_ceiling(); + return temp; + } + void in_place_ceiling(); + + /** Yields an amount whose display precision is never truncated, even + though its commodity normally displays only rounded values. */ + amount_t unrounded() const { + amount_t temp(*this); + temp.in_place_unround(); + return temp; + } + void in_place_unround(); + + /** reduces a value to its most basic commodity form, for amounts that + utilize "scaling commodities". For example, an amount of \c 1h + after reduction will be \c 3600s. + */ + amount_t reduced() const { + amount_t temp(*this); + temp.in_place_reduce(); + return temp; + } + void in_place_reduce(); + + /** unreduce(), if used with a "scaling commodity", yields the most + compact form greater than one. That is, \c 3599s will unreduce to + \c 59.98m, while \c 3601 unreduces to \c 1h. + */ + amount_t unreduced() const { + amount_t temp(*this); + temp.in_place_unreduce(); + return temp; + } + void in_place_unreduce(); + + /** Returns the historical value for an amount -- the default moment + returns the most recently known price -- based on the price history + for the given commodity (or determined automatically, if none is + provided). For example, if the amount were 10 AAPL, and + on Apr 10, 2000 each share of \c AAPL was worth \c $10, then + calling value() for that moment in time would yield the amount \c + $100.00. + */ + optional + value(const datetime_t& moment = datetime_t(), + const commodity_t * in_terms_of = NULL) const; + + optional price() const; + + /*@}*/ + + /** @name Truth tests + */ + /*@{*/ + + /** Truth tests. An amount may be truth test in several ways: + + sign() returns an integer less than, greater than, or equal to + zero depending on whether the amount is negative, zero, or + greater than zero. Note that this function tests the actual + value of the amount -- using its internal precision -- and not + the display value. To test its display value, use: + `round().sign()'. + + is_nonzero(), or operator bool, returns true if an amount's + display value is not zero. + + is_zero() returns true if an amount's display value is zero. + Thus, $0.0001 is considered zero if the current display precision + for dollars is two decimal places. + + is_realzero() returns true if an amount's actual value is zero. + Thus, $0.0001 is never considered realzero. + + is_null() returns true if an amount has no value and no + commodity. This only occurs if an uninitialized amount has never + been assigned a value. + */ + int sign() const; + + operator bool() const { + return is_nonzero(); + } + bool is_nonzero() const { + return ! is_zero(); + } + + bool is_zero() const; + bool is_realzero() const { + return sign() == 0; + } + + bool is_null() const { + if (! quantity) { + assert(! commodity_); + return true; + } + return false; + } + + /*@}*/ + + /** @name Conversion + */ + /*@{*/ + + /** Conversion methods. An amount may be converted to the same types + it can be constructed from -- with the exception of unsigned + long. Implicit conversions are not allowed in C++ (though they + are in Python), rather the following conversion methods must be + called explicitly: + + to_double([bool]) returns an amount as a double. If the optional + boolean argument is true (the default), an exception is thrown if + the conversion would lose information. + + to_long([bool]) returns an amount as a long integer. If the + optional boolean argument is true (the default), an exception is + thrown if the conversion would lose information. + + fits_in_long() returns true if to_long() would not lose + precision. + + to_string() returns an amount'ss "display value" as a string -- + after rounding the value according to the commodity's default + precision. It is equivalent to: `round().to_fullstring()'. + + to_fullstring() returns an amount's "internal value" as a string, + without any rounding. + + quantity_string() returns an amount's "display value", but + without any commodity. Note that this is different from + `number().to_string()', because in that case the commodity has + been stripped and the full, internal precision of the amount + would be displayed. + */ + double to_double() const; + long to_long() const; + bool fits_in_long() const; + + operator string() const { + return to_string(); + } + string to_string() const; + string to_fullstring() const; + string quantity_string() const; + + /*@}*/ + + /** @name Commodity methods + */ + /*@{*/ + + /** The following methods relate to an + amount's commodity: + + commodity() returns an amount's commodity. If the amount has no + commodity, the value returned is the `null_commodity'. + + has_commodity() returns true if the amount has a commodity. + + set_commodity(commodity_t) sets an amount's commodity to the + given value. Note that this merely sets the current amount to + that commodity, it does not "observe" the amount for possible + changes in the maximum display precision of the commodity, the + way that `parse' does. + + clear_commodity() sets an amount's commodity to null, such that + has_commodity() afterwards returns false. + + number() returns a commodity-less version of an amount. This is + useful for accessing just the numeric portion of an amount. + */ + commodity_t * commodity_ptr() const; + commodity_t& commodity() const { + return *commodity_ptr(); + } + + bool has_commodity() const; + void set_commodity(commodity_t& comm) { + if (! quantity) + *this = 0L; + commodity_ = &comm; + } + amount_t with_commodity(const commodity_t& comm) const { + if (commodity_ == &comm) { + return *this; + } else { + amount_t tmp(*this); + tmp.set_commodity(const_cast(comm)); + return tmp; + } + } + void clear_commodity() { + commodity_ = NULL; + } + + amount_t number() const { + if (! has_commodity()) + return *this; + + amount_t temp(*this); + temp.clear_commodity(); + return temp; + } + + /*@}*/ + + /** @name Commodity annotations + */ + /*@{*/ + + /** An amount's commodity may be annotated with special details, such as the + price it was purchased for, when it was acquired, or an arbitrary note, + identifying perhaps the lot number of an item. + + annotate_commodity(amount_t price, [datetime_t date, string tag]) + sets the annotations for the current amount's commodity. Only + the price argument is required, although it can be passed as + `none' if no price is desired. + + commodity_annotated() returns true if an amount's commodity has + any annotation details associated with it. + + annotation_details() returns all of the details of an annotated + commodity's annotations. The structure returns will evaluate as + boolean false if there are no details. + + strip_annotations() returns an amount whose commodity's annotations have + been stripped. + */ + void annotate(const annotation_t& details); + bool has_annotation() const; + + annotation_t& annotation(); + const annotation_t& annotation() const { + return const_cast(*this).annotation(); + } + + /** If the lot price is considered whenever working with commoditized + values. + + Let's say a user adds two values of the following form: + @code + 10 AAPL + 10 AAPL {$20} + @endcode + + This expression adds ten shares of Apple stock with another ten + shares that were purchased for \c $20 a share. If \c keep_price + is false, the result of this expression is an amount equal to + 20 AAPL. If \c keep_price is \c true the expression + yields an exception for adding amounts with different commodities. + In that case, a \link balance_t \endlink object must be used to + store the combined sum. */ + amount_t strip_annotations(const keep_details_t& what_to_keep) const; + + /*@}*/ + + /** @name Parsing + */ + /*@{*/ + + /** The `flags' argument of both parsing may be one or more of the + following: + + PARSE_NO_MIGRATE means to not pay attention to the way an + amount is used. Ordinarily, if an amount were $100.001, for + example, it would cause the default display precision for $ to be + "widened" to three decimal places. If PARSE_NO_MIGRATE is + used, the commodity's default display precision is not changed. + + PARSE_NO_REDUCE means not to call in_place_reduce() on the + resulting amount after it is parsed. + + These parsing methods observe the amounts they parse (unless + PARSE_NO_MIGRATE is true), and set the display details of + the corresponding commodity accordingly. This way, amounts do + not require commodities to be pre-defined in any way, but merely + displays them back to the user in the same fashion as it saw them + used. + + There is also a static convenience method called + `parse_conversion' which can be used to define a relationship + between scaling commodity values. For example, Ledger uses it to + define the relationships among various time values: + + @code + amount_t::parse_conversion("1.0m", "60s"); // a minute is 60 seconds + amount_t::parse_conversion("1.0h", "60m"); // an hour is 60 minutes + @endcode + + The method parse() is used to parse an amount from an input stream + or a string. A global operator>>() is also defined which simply + calls parse on the input stream. The parse() method has two forms: + + parse(istream, flags_t) parses an amount from the given input + stream. + + parse(string, flags_t) parses an amount from the given string. + + parse(string, flags_t) also parses an amount from a string. + */ + bool parse(std::istream& in, + const parse_flags_t& flags = PARSE_DEFAULT); + bool parse(const string& str, + const parse_flags_t& flags = PARSE_DEFAULT) { + std::istringstream stream(str); + bool result = parse(stream, flags); + return result; + } + + static void parse_conversion(const string& larger_str, + const string& smaller_str); + + /*@}*/ + + /** @name Printing + */ + /*@{*/ + + /** An amount may be output to a stream using the `print' method. There is + also a global operator<< defined which simply calls print for an amount + on the given stream. There is one form of the print method, which takes + one required argument and two arguments with default values: + + print(ostream, bool omit_commodity = false, bool full_precision = false) + prints an amounts to the given output stream, using its commodity's + default display characteristics. If `omit_commodity' is true, the + commodity will not be displayed, only the amount (although the + commodity's display precision is still used). If `full_precision' is + true, the full internal precision of the amount is displayed, regardless + of its commodity's display precision. + */ +#define AMOUNT_PRINT_NO_FLAGS 0x00 +#define AMOUNT_PRINT_RIGHT_JUSTIFY 0x01 +#define AMOUNT_PRINT_COLORIZE 0x02 +#define AMOUNT_PRINT_NO_COMPUTED_ANNOTATIONS 0x04 +#define AMOUNT_PRINT_ELIDE_COMMODITY_QUOTES 0x08 + + void print(std::ostream& out, + const uint_least8_t flags = AMOUNT_PRINT_NO_FLAGS) const; + + /*@}*/ + + /** @name Debugging + */ + /*@{*/ + + /** There are two methods defined to help with debugging: + + dump(ostream) dumps an amount to an output stream. There is + little different from print(), it simply surrounds the display + value with a marker, for example "AMOUNT($1.00)". This code is + used by other dumping code elsewhere in Ledger. + + valid() returns true if an amount is valid. This ensures that if + an amount has a commodity, it has a valid value pointer, for + example, even if that pointer simply points to a zero value. + */ + void dump(std::ostream& out) const { + out << "AMOUNT("; + print(out); + out << ")"; + } + + bool valid() const; + +#if HAVE_BOOST_SERIALIZATION +private: + /** Serialization. */ + + friend class boost::serialization::access; + + template + void serialize(Archive& ar, const unsigned int /* version */); +#endif // HAVE_BOOST_SERIALIZATION + + /*@}*/ +}; + +inline amount_t amount_t::exact(const string& value) { + amount_t temp; + temp.parse(value, PARSE_NO_MIGRATE); + return temp; +} + +inline string amount_t::to_string() const { + std::ostringstream bufstream; + print(bufstream); + return bufstream.str(); +} + +inline string amount_t::to_fullstring() const { + std::ostringstream bufstream; + unrounded().print(bufstream); + return bufstream.str(); +} + +inline string amount_t::quantity_string() const { + std::ostringstream bufstream; + number().print(bufstream); + return bufstream.str(); +} + +inline std::ostream& operator<<(std::ostream& out, const amount_t& amt) { + if (amount_t::stream_fullstrings) + amt.unrounded().print(out); + else + amt.print(out); + return out; +} +inline std::istream& operator>>(std::istream& in, amount_t& amt) { + amt.parse(in); + return in; +} + +void put_amount(property_tree::ptree& pt, const amount_t& amt, + bool wrap = true, bool commodity_details = false); + +} // namespace ledger + +#endif // _AMOUNT_H diff --git a/test/regress/25A099C9.test b/test/regress/25A099C9.test index cfc0eabd..36776520 100644 --- a/test/regress/25A099C9.test +++ b/test/regress/25A099C9.test @@ -1,61 +1,61 @@ -test -f test/garbage-input.dat reg -> 29 +test -f test/regress/25A099C9.dat reg -> 29 __ERROR__ -While parsing file "$sourcepath/test/garbage-input.dat", line 1: +While parsing file "$sourcepath/test/regress/25A099C9.dat", line 1: Error: Directive '/*' requires an argument -While parsing file "$sourcepath/test/garbage-input.dat", line 32: +While parsing file "$sourcepath/test/regress/25A099C9.dat", line 32: Error: Directive '/**' requires an argument -While parsing file "$sourcepath/test/garbage-input.dat", line 36: +While parsing file "$sourcepath/test/regress/25A099C9.dat", line 36: Error: Directive '/**' requires an argument -While parsing file "$sourcepath/test/garbage-input.dat", line 66: +While parsing file "$sourcepath/test/regress/25A099C9.dat", line 66: Error: No quantity specified for amount -While parsing file "$sourcepath/test/garbage-input.dat", line 69: +While parsing file "$sourcepath/test/regress/25A099C9.dat", line 69: Error: Unexpected whitespace at beginning of line -While parsing file "$sourcepath/test/garbage-input.dat", line 78: +While parsing file "$sourcepath/test/regress/25A099C9.dat", line 78: Error: Directive '};' requires an argument -While parsing file "$sourcepath/test/garbage-input.dat", line 82: +While parsing file "$sourcepath/test/regress/25A099C9.dat", line 82: Error: Directive '/**' requires an argument -While parsing file "$sourcepath/test/garbage-input.dat", line 93: +While parsing file "$sourcepath/test/regress/25A099C9.dat", line 93: Error: Unexpected whitespace at beginning of line -While parsing file "$sourcepath/test/garbage-input.dat", line 97: +While parsing file "$sourcepath/test/regress/25A099C9.dat", line 97: Error: Directive '{' requires an argument -While parsing file "$sourcepath/test/garbage-input.dat", line 98: +While parsing file "$sourcepath/test/regress/25A099C9.dat", line 98: Error: Directive 'public:' requires an argument -While parsing file "$sourcepath/test/garbage-input.dat", line 120: +While parsing file "$sourcepath/test/regress/25A099C9.dat", line 120: Error: Directive 'protected:' requires an argument -While parsing file "$sourcepath/test/garbage-input.dat", line 131: +While parsing file "$sourcepath/test/regress/25A099C9.dat", line 131: Error: Directive 'public:' requires an argument -While parsing file "$sourcepath/test/garbage-input.dat", line 711: +While parsing file "$sourcepath/test/regress/25A099C9.dat", line 711: Error: Unexpected whitespace at beginning of line -While parsing file "$sourcepath/test/garbage-input.dat", line 740: +While parsing file "$sourcepath/test/regress/25A099C9.dat", line 740: Error: Directive 'private:' requires an argument -While parsing file "$sourcepath/test/garbage-input.dat", line 749: +While parsing file "$sourcepath/test/regress/25A099C9.dat", line 749: Error: Unexpected whitespace at beginning of line -While parsing file "$sourcepath/test/garbage-input.dat", line 750: +While parsing file "$sourcepath/test/regress/25A099C9.dat", line 750: Error: Directive '};' requires an argument -While parsing file "$sourcepath/test/garbage-input.dat", line 752: +While parsing file "$sourcepath/test/regress/25A099C9.dat", line 752: Error: Invalid date/time: line amount_t amoun -While parsing file "$sourcepath/test/garbage-input.dat", line 756: +While parsing file "$sourcepath/test/regress/25A099C9.dat", line 756: Error: Directive '}' requires an argument -While parsing file "$sourcepath/test/garbage-input.dat", line 758: +While parsing file "$sourcepath/test/regress/25A099C9.dat", line 758: Error: Invalid date/time: line string amount_ -While parsing file "$sourcepath/test/garbage-input.dat", line 762: +While parsing file "$sourcepath/test/regress/25A099C9.dat", line 762: Error: Directive '}' requires an argument -While parsing file "$sourcepath/test/garbage-input.dat", line 764: +While parsing file "$sourcepath/test/regress/25A099C9.dat", line 764: Error: Invalid date/time: line string amount_ -While parsing file "$sourcepath/test/garbage-input.dat", line 768: +While parsing file "$sourcepath/test/regress/25A099C9.dat", line 768: Error: Directive '}' requires an argument -While parsing file "$sourcepath/test/garbage-input.dat", line 770: +While parsing file "$sourcepath/test/regress/25A099C9.dat", line 770: Error: Invalid date/time: line string amount_ -While parsing file "$sourcepath/test/garbage-input.dat", line 774: +While parsing file "$sourcepath/test/regress/25A099C9.dat", line 774: Error: Directive '}' requires an argument -While parsing file "$sourcepath/test/garbage-input.dat", line 776: +While parsing file "$sourcepath/test/regress/25A099C9.dat", line 776: Error: Invalid date/time: line std::ostream& -While parsing file "$sourcepath/test/garbage-input.dat", line 782: +While parsing file "$sourcepath/test/regress/25A099C9.dat", line 782: Error: Directive '}' requires an argument -While parsing file "$sourcepath/test/garbage-input.dat", line 783: +While parsing file "$sourcepath/test/regress/25A099C9.dat", line 783: Error: Invalid date/time: line std::istream& -While parsing file "$sourcepath/test/garbage-input.dat", line 786: +While parsing file "$sourcepath/test/regress/25A099C9.dat", line 786: Error: Directive '}' requires an argument -While parsing file "$sourcepath/test/garbage-input.dat", line 789: +While parsing file "$sourcepath/test/regress/25A099C9.dat", line 789: Error: Unexpected whitespace at beginning of line end test -- cgit v1.2.3